Merge remote-tracking branch 'origin/develop' into features/mastoapi/2.6.0-conversations
[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.User
14 alias Pleroma.Web.ActivityPub.ActivityPub
15 alias Pleroma.Web.CommonAPI
16 alias Pleroma.Web.MastodonAPI.FilterView
17 alias Pleroma.Web.OStatus
18 alias Pleroma.Web.TwitterAPI.TwitterAPI
19 import Pleroma.Factory
20 import ExUnit.CaptureLog
21 import Tesla.Mock
22
23 setup do
24 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
25 :ok
26 end
27
28 test "the home timeline", %{conn: conn} do
29 user = insert(:user)
30 following = insert(:user)
31
32 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
33
34 conn =
35 conn
36 |> assign(:user, user)
37 |> get("/api/v1/timelines/home")
38
39 assert Enum.empty?(json_response(conn, 200))
40
41 {:ok, user} = User.follow(user, following)
42
43 conn =
44 build_conn()
45 |> assign(:user, user)
46 |> get("/api/v1/timelines/home")
47
48 assert [%{"content" => "test"}] = json_response(conn, 200)
49 end
50
51 test "the public timeline", %{conn: conn} do
52 following = insert(:user)
53
54 capture_log(fn ->
55 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
56
57 {:ok, [_activity]} =
58 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
59
60 conn =
61 conn
62 |> get("/api/v1/timelines/public", %{"local" => "False"})
63
64 assert length(json_response(conn, 200)) == 2
65
66 conn =
67 build_conn()
68 |> get("/api/v1/timelines/public", %{"local" => "True"})
69
70 assert [%{"content" => "test"}] = json_response(conn, 200)
71
72 conn =
73 build_conn()
74 |> get("/api/v1/timelines/public", %{"local" => "1"})
75
76 assert [%{"content" => "test"}] = json_response(conn, 200)
77 end)
78 end
79
80 test "posting a status", %{conn: conn} do
81 user = insert(:user)
82
83 idempotency_key = "Pikachu rocks!"
84
85 conn_one =
86 conn
87 |> assign(:user, user)
88 |> put_req_header("idempotency-key", idempotency_key)
89 |> post("/api/v1/statuses", %{
90 "status" => "cofe",
91 "spoiler_text" => "2hu",
92 "sensitive" => "false"
93 })
94
95 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
96 # Six hours
97 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
98
99 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
100 json_response(conn_one, 200)
101
102 assert Repo.get(Activity, id)
103
104 conn_two =
105 conn
106 |> assign(:user, user)
107 |> put_req_header("idempotency-key", idempotency_key)
108 |> post("/api/v1/statuses", %{
109 "status" => "cofe",
110 "spoiler_text" => "2hu",
111 "sensitive" => "false"
112 })
113
114 assert %{"id" => second_id} = json_response(conn_two, 200)
115
116 assert id == second_id
117
118 conn_three =
119 conn
120 |> assign(:user, user)
121 |> post("/api/v1/statuses", %{
122 "status" => "cofe",
123 "spoiler_text" => "2hu",
124 "sensitive" => "false"
125 })
126
127 assert %{"id" => third_id} = json_response(conn_three, 200)
128
129 refute id == third_id
130 end
131
132 test "posting a sensitive status", %{conn: conn} do
133 user = insert(:user)
134
135 conn =
136 conn
137 |> assign(:user, user)
138 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
139
140 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
141 assert Repo.get(Activity, id)
142 end
143
144 test "posting a status with OGP link preview", %{conn: conn} do
145 Pleroma.Config.put([:rich_media, :enabled], true)
146 user = insert(:user)
147
148 conn =
149 conn
150 |> assign(:user, user)
151 |> post("/api/v1/statuses", %{
152 "status" => "http://example.com/ogp"
153 })
154
155 assert %{"id" => id, "card" => %{"title" => "The Rock"}} = json_response(conn, 200)
156 assert Repo.get(Activity, id)
157 Pleroma.Config.put([:rich_media, :enabled], false)
158 end
159
160 test "posting a direct status", %{conn: conn} do
161 user1 = insert(:user)
162 user2 = insert(:user)
163 content = "direct cofe @#{user2.nickname}"
164
165 conn =
166 conn
167 |> assign(:user, user1)
168 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
169
170 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
171 assert activity = Repo.get(Activity, id)
172 assert activity.recipients == [user2.ap_id, user1.ap_id]
173 assert activity.data["to"] == [user2.ap_id]
174 assert activity.data["cc"] == []
175 end
176
177 test "direct timeline", %{conn: conn} do
178 user_one = insert(:user)
179 user_two = insert(:user)
180
181 {:ok, user_two} = User.follow(user_two, user_one)
182
183 {:ok, direct} =
184 CommonAPI.post(user_one, %{
185 "status" => "Hi @#{user_two.nickname}!",
186 "visibility" => "direct"
187 })
188
189 {:ok, _follower_only} =
190 CommonAPI.post(user_one, %{
191 "status" => "Hi @#{user_two.nickname}!",
192 "visibility" => "private"
193 })
194
195 # Only direct should be visible here
196 res_conn =
197 conn
198 |> assign(:user, user_two)
199 |> get("api/v1/timelines/direct")
200
201 [status] = json_response(res_conn, 200)
202
203 assert %{"visibility" => "direct"} = status
204 assert status["url"] != direct.data["id"]
205
206 # User should be able to see his own direct message
207 res_conn =
208 build_conn()
209 |> assign(:user, user_one)
210 |> get("api/v1/timelines/direct")
211
212 [status] = json_response(res_conn, 200)
213
214 assert %{"visibility" => "direct"} = status
215
216 # Both should be visible here
217 res_conn =
218 conn
219 |> assign(:user, user_two)
220 |> get("api/v1/timelines/home")
221
222 [_s1, _s2] = json_response(res_conn, 200)
223
224 # Test pagination
225 Enum.each(1..20, fn _ ->
226 {:ok, _} =
227 CommonAPI.post(user_one, %{
228 "status" => "Hi @#{user_two.nickname}!",
229 "visibility" => "direct"
230 })
231 end)
232
233 res_conn =
234 conn
235 |> assign(:user, user_two)
236 |> get("api/v1/timelines/direct")
237
238 statuses = json_response(res_conn, 200)
239 assert length(statuses) == 20
240
241 res_conn =
242 conn
243 |> assign(:user, user_two)
244 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
245
246 [status] = json_response(res_conn, 200)
247
248 assert status["url"] != direct.data["id"]
249 end
250
251 test "Conversations", %{conn: conn} do
252 user_one = insert(:user)
253 user_two = insert(:user)
254
255 {:ok, user_two} = User.follow(user_two, user_one)
256
257 {:ok, direct} =
258 CommonAPI.post(user_one, %{
259 "status" => "Hi @#{user_two.nickname}!",
260 "visibility" => "direct"
261 })
262
263 {:ok, _follower_only} =
264 CommonAPI.post(user_one, %{
265 "status" => "Hi @#{user_two.nickname}!",
266 "visibility" => "private"
267 })
268
269 res_conn =
270 conn
271 |> assign(:user, user)
272 |> get("/api/v1/conversations")
273
274 assert response = json_response(res_conn, 200)
275
276 assert %{
277 "id" => res_id,
278 "accounts" => res_accounts,
279 "last_status" => res_last_status,
280 "unread" => unread
281 } = reponse
282
283 assert unread == false
284
285 # Apparently undocumented API endpoint
286 res_conn =
287 conn
288 |> assign(:user, user)
289 |> get("/api/v1/conversations/#{res_id}/read")
290
291 assert response == json_response(res_conn, 200)
292
293 # (vanilla) Mastodon frontend behaviour
294 res_conn =
295 conn
296 |> assign(:user, user)
297 |> get("/api/v1/statuses/#{res_last_status.id}/context")
298
299 assert %{ancestors: [], descendants: []} == json_response(res_conn, 200)
300 end
301
302 test "doesn't include DMs from blocked users", %{conn: conn} do
303 blocker = insert(:user)
304 blocked = insert(:user)
305 user = insert(:user)
306 {:ok, blocker} = User.block(blocker, blocked)
307
308 {:ok, _blocked_direct} =
309 CommonAPI.post(blocked, %{
310 "status" => "Hi @#{blocker.nickname}!",
311 "visibility" => "direct"
312 })
313
314 {:ok, direct} =
315 CommonAPI.post(user, %{
316 "status" => "Hi @#{blocker.nickname}!",
317 "visibility" => "direct"
318 })
319
320 res_conn =
321 conn
322 |> assign(:user, user)
323 |> get("api/v1/timelines/direct")
324
325 [status] = json_response(res_conn, 200)
326 assert status["id"] == direct.id
327 end
328
329 test "replying to a status", %{conn: conn} do
330 user = insert(:user)
331
332 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
333
334 conn =
335 conn
336 |> assign(:user, user)
337 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
338
339 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
340
341 activity = Repo.get(Activity, id)
342
343 assert activity.data["context"] == replied_to.data["context"]
344 assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
345 end
346
347 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
348 user = insert(:user)
349
350 conn =
351 conn
352 |> assign(:user, user)
353 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
354
355 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
356
357 activity = Repo.get(Activity, id)
358
359 assert activity
360 end
361
362 test "verify_credentials", %{conn: conn} do
363 user = insert(:user)
364
365 conn =
366 conn
367 |> assign(:user, user)
368 |> get("/api/v1/accounts/verify_credentials")
369
370 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
371 assert id == to_string(user.id)
372 end
373
374 test "verify_credentials default scope unlisted", %{conn: conn} do
375 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
376
377 conn =
378 conn
379 |> assign(:user, user)
380 |> get("/api/v1/accounts/verify_credentials")
381
382 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
383 assert id == to_string(user.id)
384 end
385
386 test "get a status", %{conn: conn} do
387 activity = insert(:note_activity)
388
389 conn =
390 conn
391 |> get("/api/v1/statuses/#{activity.id}")
392
393 assert %{"id" => id} = json_response(conn, 200)
394 assert id == to_string(activity.id)
395 end
396
397 describe "deleting a status" do
398 test "when you created it", %{conn: conn} do
399 activity = insert(:note_activity)
400 author = User.get_by_ap_id(activity.data["actor"])
401
402 conn =
403 conn
404 |> assign(:user, author)
405 |> delete("/api/v1/statuses/#{activity.id}")
406
407 assert %{} = json_response(conn, 200)
408
409 refute Repo.get(Activity, activity.id)
410 end
411
412 test "when you didn't create it", %{conn: conn} do
413 activity = insert(:note_activity)
414 user = insert(:user)
415
416 conn =
417 conn
418 |> assign(:user, user)
419 |> delete("/api/v1/statuses/#{activity.id}")
420
421 assert %{"error" => _} = json_response(conn, 403)
422
423 assert Repo.get(Activity, activity.id) == activity
424 end
425
426 test "when you're an admin or moderator", %{conn: conn} do
427 activity1 = insert(:note_activity)
428 activity2 = insert(:note_activity)
429 admin = insert(:user, info: %{is_admin: true})
430 moderator = insert(:user, info: %{is_moderator: true})
431
432 res_conn =
433 conn
434 |> assign(:user, admin)
435 |> delete("/api/v1/statuses/#{activity1.id}")
436
437 assert %{} = json_response(res_conn, 200)
438
439 res_conn =
440 conn
441 |> assign(:user, moderator)
442 |> delete("/api/v1/statuses/#{activity2.id}")
443
444 assert %{} = json_response(res_conn, 200)
445
446 refute Repo.get(Activity, activity1.id)
447 refute Repo.get(Activity, activity2.id)
448 end
449 end
450
451 describe "filters" do
452 test "creating a filter", %{conn: conn} do
453 user = insert(:user)
454
455 filter = %Pleroma.Filter{
456 phrase: "knights",
457 context: ["home"]
458 }
459
460 conn =
461 conn
462 |> assign(:user, user)
463 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
464
465 assert response = json_response(conn, 200)
466 assert response["phrase"] == filter.phrase
467 assert response["context"] == filter.context
468 assert response["id"] != nil
469 assert response["id"] != ""
470 end
471
472 test "fetching a list of filters", %{conn: conn} do
473 user = insert(:user)
474
475 query_one = %Pleroma.Filter{
476 user_id: user.id,
477 filter_id: 1,
478 phrase: "knights",
479 context: ["home"]
480 }
481
482 query_two = %Pleroma.Filter{
483 user_id: user.id,
484 filter_id: 2,
485 phrase: "who",
486 context: ["home"]
487 }
488
489 {:ok, filter_one} = Pleroma.Filter.create(query_one)
490 {:ok, filter_two} = Pleroma.Filter.create(query_two)
491
492 response =
493 conn
494 |> assign(:user, user)
495 |> get("/api/v1/filters")
496 |> json_response(200)
497
498 assert response ==
499 render_json(
500 FilterView,
501 "filters.json",
502 filters: [filter_two, filter_one]
503 )
504 end
505
506 test "get a filter", %{conn: conn} do
507 user = insert(:user)
508
509 query = %Pleroma.Filter{
510 user_id: user.id,
511 filter_id: 2,
512 phrase: "knight",
513 context: ["home"]
514 }
515
516 {:ok, filter} = Pleroma.Filter.create(query)
517
518 conn =
519 conn
520 |> assign(:user, user)
521 |> get("/api/v1/filters/#{filter.filter_id}")
522
523 assert _response = json_response(conn, 200)
524 end
525
526 test "update a filter", %{conn: conn} do
527 user = insert(:user)
528
529 query = %Pleroma.Filter{
530 user_id: user.id,
531 filter_id: 2,
532 phrase: "knight",
533 context: ["home"]
534 }
535
536 {:ok, _filter} = Pleroma.Filter.create(query)
537
538 new = %Pleroma.Filter{
539 phrase: "nii",
540 context: ["home"]
541 }
542
543 conn =
544 conn
545 |> assign(:user, user)
546 |> put("/api/v1/filters/#{query.filter_id}", %{
547 phrase: new.phrase,
548 context: new.context
549 })
550
551 assert response = json_response(conn, 200)
552 assert response["phrase"] == new.phrase
553 assert response["context"] == new.context
554 end
555
556 test "delete a filter", %{conn: conn} do
557 user = insert(:user)
558
559 query = %Pleroma.Filter{
560 user_id: user.id,
561 filter_id: 2,
562 phrase: "knight",
563 context: ["home"]
564 }
565
566 {:ok, filter} = Pleroma.Filter.create(query)
567
568 conn =
569 conn
570 |> assign(:user, user)
571 |> delete("/api/v1/filters/#{filter.filter_id}")
572
573 assert response = json_response(conn, 200)
574 assert response == %{}
575 end
576 end
577
578 describe "lists" do
579 test "creating a list", %{conn: conn} do
580 user = insert(:user)
581
582 conn =
583 conn
584 |> assign(:user, user)
585 |> post("/api/v1/lists", %{"title" => "cuties"})
586
587 assert %{"title" => title} = json_response(conn, 200)
588 assert title == "cuties"
589 end
590
591 test "adding users to a list", %{conn: conn} do
592 user = insert(:user)
593 other_user = insert(:user)
594 {:ok, list} = Pleroma.List.create("name", user)
595
596 conn =
597 conn
598 |> assign(:user, user)
599 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
600
601 assert %{} == json_response(conn, 200)
602 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
603 assert following == [other_user.follower_address]
604 end
605
606 test "removing users from a list", %{conn: conn} do
607 user = insert(:user)
608 other_user = insert(:user)
609 third_user = insert(:user)
610 {:ok, list} = Pleroma.List.create("name", user)
611 {:ok, list} = Pleroma.List.follow(list, other_user)
612 {:ok, list} = Pleroma.List.follow(list, third_user)
613
614 conn =
615 conn
616 |> assign(:user, user)
617 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
618
619 assert %{} == json_response(conn, 200)
620 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
621 assert following == [third_user.follower_address]
622 end
623
624 test "listing users in a list", %{conn: conn} do
625 user = insert(:user)
626 other_user = insert(:user)
627 {:ok, list} = Pleroma.List.create("name", user)
628 {:ok, list} = Pleroma.List.follow(list, other_user)
629
630 conn =
631 conn
632 |> assign(:user, user)
633 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
634
635 assert [%{"id" => id}] = json_response(conn, 200)
636 assert id == to_string(other_user.id)
637 end
638
639 test "retrieving a list", %{conn: conn} do
640 user = insert(:user)
641 {:ok, list} = Pleroma.List.create("name", user)
642
643 conn =
644 conn
645 |> assign(:user, user)
646 |> get("/api/v1/lists/#{list.id}")
647
648 assert %{"id" => id} = json_response(conn, 200)
649 assert id == to_string(list.id)
650 end
651
652 test "renaming a list", %{conn: conn} do
653 user = insert(:user)
654 {:ok, list} = Pleroma.List.create("name", user)
655
656 conn =
657 conn
658 |> assign(:user, user)
659 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
660
661 assert %{"title" => name} = json_response(conn, 200)
662 assert name == "newname"
663 end
664
665 test "deleting a list", %{conn: conn} do
666 user = insert(:user)
667 {:ok, list} = Pleroma.List.create("name", user)
668
669 conn =
670 conn
671 |> assign(:user, user)
672 |> delete("/api/v1/lists/#{list.id}")
673
674 assert %{} = json_response(conn, 200)
675 assert is_nil(Repo.get(Pleroma.List, list.id))
676 end
677
678 test "list timeline", %{conn: conn} do
679 user = insert(:user)
680 other_user = insert(:user)
681 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
682 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
683 {:ok, list} = Pleroma.List.create("name", user)
684 {:ok, list} = Pleroma.List.follow(list, other_user)
685
686 conn =
687 conn
688 |> assign(:user, user)
689 |> get("/api/v1/timelines/list/#{list.id}")
690
691 assert [%{"id" => id}] = json_response(conn, 200)
692
693 assert id == to_string(activity_two.id)
694 end
695
696 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
697 user = insert(:user)
698 other_user = insert(:user)
699 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
700
701 {:ok, _activity_two} =
702 TwitterAPI.create_status(other_user, %{
703 "status" => "Marisa is cute.",
704 "visibility" => "private"
705 })
706
707 {:ok, list} = Pleroma.List.create("name", user)
708 {:ok, list} = Pleroma.List.follow(list, other_user)
709
710 conn =
711 conn
712 |> assign(:user, user)
713 |> get("/api/v1/timelines/list/#{list.id}")
714
715 assert [%{"id" => id}] = json_response(conn, 200)
716
717 assert id == to_string(activity_one.id)
718 end
719 end
720
721 describe "notifications" do
722 test "list of notifications", %{conn: conn} do
723 user = insert(:user)
724 other_user = insert(:user)
725
726 {:ok, activity} =
727 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
728
729 {:ok, [_notification]} = Notification.create_notifications(activity)
730
731 conn =
732 conn
733 |> assign(:user, user)
734 |> get("/api/v1/notifications")
735
736 expected_response =
737 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
738 user.ap_id
739 }\">@<span>#{user.nickname}</span></a></span>"
740
741 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
742 assert response == expected_response
743 end
744
745 test "getting a single notification", %{conn: conn} do
746 user = insert(:user)
747 other_user = insert(:user)
748
749 {:ok, activity} =
750 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
751
752 {:ok, [notification]} = Notification.create_notifications(activity)
753
754 conn =
755 conn
756 |> assign(:user, user)
757 |> get("/api/v1/notifications/#{notification.id}")
758
759 expected_response =
760 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
761 user.ap_id
762 }\">@<span>#{user.nickname}</span></a></span>"
763
764 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
765 assert response == expected_response
766 end
767
768 test "dismissing a single notification", %{conn: conn} do
769 user = insert(:user)
770 other_user = insert(:user)
771
772 {:ok, activity} =
773 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
774
775 {:ok, [notification]} = Notification.create_notifications(activity)
776
777 conn =
778 conn
779 |> assign(:user, user)
780 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
781
782 assert %{} = json_response(conn, 200)
783 end
784
785 test "clearing all notifications", %{conn: conn} do
786 user = insert(:user)
787 other_user = insert(:user)
788
789 {:ok, activity} =
790 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
791
792 {:ok, [_notification]} = Notification.create_notifications(activity)
793
794 conn =
795 conn
796 |> assign(:user, user)
797 |> post("/api/v1/notifications/clear")
798
799 assert %{} = json_response(conn, 200)
800
801 conn =
802 build_conn()
803 |> assign(:user, user)
804 |> get("/api/v1/notifications")
805
806 assert all = json_response(conn, 200)
807 assert all == []
808 end
809
810 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
811 user = insert(:user)
812 other_user = insert(:user)
813
814 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
815 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
816 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
817 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
818
819 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
820 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
821 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
822 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
823
824 conn =
825 conn
826 |> assign(:user, user)
827
828 # min_id
829 conn_res =
830 conn
831 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
832
833 result = json_response(conn_res, 200)
834 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
835
836 # since_id
837 conn_res =
838 conn
839 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
840
841 result = json_response(conn_res, 200)
842 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
843
844 # max_id
845 conn_res =
846 conn
847 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
848
849 result = json_response(conn_res, 200)
850 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
851 end
852
853 test "filters notifications using exclude_types", %{conn: conn} do
854 user = insert(:user)
855 other_user = insert(:user)
856
857 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
858 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
859 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
860 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
861 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
862
863 mention_notification_id =
864 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
865
866 favorite_notification_id =
867 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
868
869 reblog_notification_id =
870 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
871
872 follow_notification_id =
873 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
874
875 conn =
876 conn
877 |> assign(:user, user)
878
879 conn_res =
880 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
881
882 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
883
884 conn_res =
885 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
886
887 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
888
889 conn_res =
890 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
891
892 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
893
894 conn_res =
895 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
896
897 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
898 end
899 end
900
901 describe "reblogging" do
902 test "reblogs and returns the reblogged status", %{conn: conn} do
903 activity = insert(:note_activity)
904 user = insert(:user)
905
906 conn =
907 conn
908 |> assign(:user, user)
909 |> post("/api/v1/statuses/#{activity.id}/reblog")
910
911 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
912 json_response(conn, 200)
913
914 assert to_string(activity.id) == id
915 end
916 end
917
918 describe "unreblogging" do
919 test "unreblogs and returns the unreblogged status", %{conn: conn} do
920 activity = insert(:note_activity)
921 user = insert(:user)
922
923 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
924
925 conn =
926 conn
927 |> assign(:user, user)
928 |> post("/api/v1/statuses/#{activity.id}/unreblog")
929
930 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
931
932 assert to_string(activity.id) == id
933 end
934 end
935
936 describe "favoriting" do
937 test "favs a status and returns it", %{conn: conn} do
938 activity = insert(:note_activity)
939 user = insert(:user)
940
941 conn =
942 conn
943 |> assign(:user, user)
944 |> post("/api/v1/statuses/#{activity.id}/favourite")
945
946 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
947 json_response(conn, 200)
948
949 assert to_string(activity.id) == id
950 end
951
952 test "returns 500 for a wrong id", %{conn: conn} do
953 user = insert(:user)
954
955 resp =
956 conn
957 |> assign(:user, user)
958 |> post("/api/v1/statuses/1/favourite")
959 |> json_response(500)
960
961 assert resp == "Something went wrong"
962 end
963 end
964
965 describe "unfavoriting" do
966 test "unfavorites a status and returns it", %{conn: conn} do
967 activity = insert(:note_activity)
968 user = insert(:user)
969
970 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
971
972 conn =
973 conn
974 |> assign(:user, user)
975 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
976
977 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
978 json_response(conn, 200)
979
980 assert to_string(activity.id) == id
981 end
982 end
983
984 describe "user timelines" do
985 test "gets a users statuses", %{conn: conn} do
986 user_one = insert(:user)
987 user_two = insert(:user)
988 user_three = insert(:user)
989
990 {:ok, user_three} = User.follow(user_three, user_one)
991
992 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
993
994 {:ok, direct_activity} =
995 CommonAPI.post(user_one, %{
996 "status" => "Hi, @#{user_two.nickname}.",
997 "visibility" => "direct"
998 })
999
1000 {:ok, private_activity} =
1001 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1002
1003 resp =
1004 conn
1005 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1006
1007 assert [%{"id" => id}] = json_response(resp, 200)
1008 assert id == to_string(activity.id)
1009
1010 resp =
1011 conn
1012 |> assign(:user, user_two)
1013 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1014
1015 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1016 assert id_one == to_string(direct_activity.id)
1017 assert id_two == to_string(activity.id)
1018
1019 resp =
1020 conn
1021 |> assign(:user, user_three)
1022 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1023
1024 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1025 assert id_one == to_string(private_activity.id)
1026 assert id_two == to_string(activity.id)
1027 end
1028
1029 test "unimplemented pinned statuses feature", %{conn: conn} do
1030 note = insert(:note_activity)
1031 user = User.get_by_ap_id(note.data["actor"])
1032
1033 conn =
1034 conn
1035 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1036
1037 assert json_response(conn, 200) == []
1038 end
1039
1040 test "gets an users media", %{conn: conn} do
1041 note = insert(:note_activity)
1042 user = User.get_by_ap_id(note.data["actor"])
1043
1044 file = %Plug.Upload{
1045 content_type: "image/jpg",
1046 path: Path.absname("test/fixtures/image.jpg"),
1047 filename: "an_image.jpg"
1048 }
1049
1050 media =
1051 TwitterAPI.upload(file, user, "json")
1052 |> Poison.decode!()
1053
1054 {:ok, image_post} =
1055 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1056
1057 conn =
1058 conn
1059 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1060
1061 assert [%{"id" => id}] = json_response(conn, 200)
1062 assert id == to_string(image_post.id)
1063
1064 conn =
1065 build_conn()
1066 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1067
1068 assert [%{"id" => id}] = json_response(conn, 200)
1069 assert id == to_string(image_post.id)
1070 end
1071
1072 test "gets a user's statuses without reblogs", %{conn: conn} do
1073 user = insert(:user)
1074 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1075 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1076
1077 conn =
1078 conn
1079 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1080
1081 assert [%{"id" => id}] = json_response(conn, 200)
1082 assert id == to_string(post.id)
1083
1084 conn =
1085 conn
1086 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1087
1088 assert [%{"id" => id}] = json_response(conn, 200)
1089 assert id == to_string(post.id)
1090 end
1091 end
1092
1093 describe "user relationships" do
1094 test "returns the relationships for the current user", %{conn: conn} do
1095 user = insert(:user)
1096 other_user = insert(:user)
1097 {:ok, user} = User.follow(user, other_user)
1098
1099 conn =
1100 conn
1101 |> assign(:user, user)
1102 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1103
1104 assert [relationship] = json_response(conn, 200)
1105
1106 assert to_string(other_user.id) == relationship["id"]
1107 end
1108 end
1109
1110 describe "locked accounts" do
1111 test "/api/v1/follow_requests works" do
1112 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1113 other_user = insert(:user)
1114
1115 {:ok, _activity} = ActivityPub.follow(other_user, user)
1116
1117 user = Repo.get(User, user.id)
1118 other_user = Repo.get(User, other_user.id)
1119
1120 assert User.following?(other_user, user) == false
1121
1122 conn =
1123 build_conn()
1124 |> assign(:user, user)
1125 |> get("/api/v1/follow_requests")
1126
1127 assert [relationship] = json_response(conn, 200)
1128 assert to_string(other_user.id) == relationship["id"]
1129 end
1130
1131 test "/api/v1/follow_requests/:id/authorize works" do
1132 user = insert(:user, %{info: %User.Info{locked: true}})
1133 other_user = insert(:user)
1134
1135 {:ok, _activity} = ActivityPub.follow(other_user, user)
1136
1137 user = Repo.get(User, user.id)
1138 other_user = Repo.get(User, other_user.id)
1139
1140 assert User.following?(other_user, user) == false
1141
1142 conn =
1143 build_conn()
1144 |> assign(:user, user)
1145 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1146
1147 assert relationship = json_response(conn, 200)
1148 assert to_string(other_user.id) == relationship["id"]
1149
1150 user = Repo.get(User, user.id)
1151 other_user = Repo.get(User, other_user.id)
1152
1153 assert User.following?(other_user, user) == true
1154 end
1155
1156 test "verify_credentials", %{conn: conn} do
1157 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1158
1159 conn =
1160 conn
1161 |> assign(:user, user)
1162 |> get("/api/v1/accounts/verify_credentials")
1163
1164 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1165 assert id == to_string(user.id)
1166 end
1167
1168 test "/api/v1/follow_requests/:id/reject works" do
1169 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1170 other_user = insert(:user)
1171
1172 {:ok, _activity} = ActivityPub.follow(other_user, user)
1173
1174 user = Repo.get(User, user.id)
1175
1176 conn =
1177 build_conn()
1178 |> assign(:user, user)
1179 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1180
1181 assert relationship = json_response(conn, 200)
1182 assert to_string(other_user.id) == relationship["id"]
1183
1184 user = Repo.get(User, user.id)
1185 other_user = Repo.get(User, other_user.id)
1186
1187 assert User.following?(other_user, user) == false
1188 end
1189 end
1190
1191 test "account fetching", %{conn: conn} do
1192 user = insert(:user)
1193
1194 conn =
1195 conn
1196 |> get("/api/v1/accounts/#{user.id}")
1197
1198 assert %{"id" => id} = json_response(conn, 200)
1199 assert id == to_string(user.id)
1200
1201 conn =
1202 build_conn()
1203 |> get("/api/v1/accounts/-1")
1204
1205 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1206 end
1207
1208 test "account fetching also works nickname", %{conn: conn} do
1209 user = insert(:user)
1210
1211 conn =
1212 conn
1213 |> get("/api/v1/accounts/#{user.nickname}")
1214
1215 assert %{"id" => id} = json_response(conn, 200)
1216 assert id == user.id
1217 end
1218
1219 test "media upload", %{conn: conn} do
1220 file = %Plug.Upload{
1221 content_type: "image/jpg",
1222 path: Path.absname("test/fixtures/image.jpg"),
1223 filename: "an_image.jpg"
1224 }
1225
1226 desc = "Description of the image"
1227
1228 user = insert(:user)
1229
1230 conn =
1231 conn
1232 |> assign(:user, user)
1233 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1234
1235 assert media = json_response(conn, 200)
1236
1237 assert media["type"] == "image"
1238 assert media["description"] == desc
1239 assert media["id"]
1240
1241 object = Repo.get(Object, media["id"])
1242 assert object.data["actor"] == User.ap_id(user)
1243 end
1244
1245 test "hashtag timeline", %{conn: conn} do
1246 following = insert(:user)
1247
1248 capture_log(fn ->
1249 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1250
1251 {:ok, [_activity]} =
1252 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1253
1254 nconn =
1255 conn
1256 |> get("/api/v1/timelines/tag/2hu")
1257
1258 assert [%{"id" => id}] = json_response(nconn, 200)
1259
1260 assert id == to_string(activity.id)
1261
1262 # works for different capitalization too
1263 nconn =
1264 conn
1265 |> get("/api/v1/timelines/tag/2HU")
1266
1267 assert [%{"id" => id}] = json_response(nconn, 200)
1268
1269 assert id == to_string(activity.id)
1270 end)
1271 end
1272
1273 test "multi-hashtag timeline", %{conn: conn} do
1274 user = insert(:user)
1275
1276 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1277 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1278 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1279
1280 any_test =
1281 conn
1282 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1283
1284 [status_none, status_test1, status_test] = json_response(any_test, 200)
1285
1286 assert to_string(activity_test.id) == status_test["id"]
1287 assert to_string(activity_test1.id) == status_test1["id"]
1288 assert to_string(activity_none.id) == status_none["id"]
1289
1290 restricted_test =
1291 conn
1292 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1293
1294 assert [status_test1] == json_response(restricted_test, 200)
1295
1296 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1297
1298 assert [status_none] == json_response(all_test, 200)
1299 end
1300
1301 test "getting followers", %{conn: conn} do
1302 user = insert(:user)
1303 other_user = insert(:user)
1304 {:ok, user} = User.follow(user, other_user)
1305
1306 conn =
1307 conn
1308 |> get("/api/v1/accounts/#{other_user.id}/followers")
1309
1310 assert [%{"id" => id}] = json_response(conn, 200)
1311 assert id == to_string(user.id)
1312 end
1313
1314 test "getting followers, hide_followers", %{conn: conn} do
1315 user = insert(:user)
1316 other_user = insert(:user, %{info: %{hide_followers: true}})
1317 {:ok, _user} = User.follow(user, other_user)
1318
1319 conn =
1320 conn
1321 |> get("/api/v1/accounts/#{other_user.id}/followers")
1322
1323 assert [] == json_response(conn, 200)
1324 end
1325
1326 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1327 user = insert(:user)
1328 other_user = insert(:user, %{info: %{hide_followers: true}})
1329 {:ok, _user} = User.follow(user, other_user)
1330
1331 conn =
1332 conn
1333 |> assign(:user, other_user)
1334 |> get("/api/v1/accounts/#{other_user.id}/followers")
1335
1336 refute [] == json_response(conn, 200)
1337 end
1338
1339 test "getting followers, pagination", %{conn: conn} do
1340 user = insert(:user)
1341 follower1 = insert(:user)
1342 follower2 = insert(:user)
1343 follower3 = insert(:user)
1344 {:ok, _} = User.follow(follower1, user)
1345 {:ok, _} = User.follow(follower2, user)
1346 {:ok, _} = User.follow(follower3, user)
1347
1348 conn =
1349 conn
1350 |> assign(:user, user)
1351
1352 res_conn =
1353 conn
1354 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1355
1356 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1357 assert id3 == follower3.id
1358 assert id2 == follower2.id
1359
1360 res_conn =
1361 conn
1362 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1363
1364 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1365 assert id2 == follower2.id
1366 assert id1 == follower1.id
1367
1368 res_conn =
1369 conn
1370 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1371
1372 assert [%{"id" => id2}] = json_response(res_conn, 200)
1373 assert id2 == follower2.id
1374
1375 assert [link_header] = get_resp_header(res_conn, "link")
1376 assert link_header =~ ~r/since_id=#{follower2.id}/
1377 assert link_header =~ ~r/max_id=#{follower2.id}/
1378 end
1379
1380 test "getting following", %{conn: conn} do
1381 user = insert(:user)
1382 other_user = insert(:user)
1383 {:ok, user} = User.follow(user, other_user)
1384
1385 conn =
1386 conn
1387 |> get("/api/v1/accounts/#{user.id}/following")
1388
1389 assert [%{"id" => id}] = json_response(conn, 200)
1390 assert id == to_string(other_user.id)
1391 end
1392
1393 test "getting following, hide_follows", %{conn: conn} do
1394 user = insert(:user, %{info: %{hide_follows: true}})
1395 other_user = insert(:user)
1396 {:ok, user} = User.follow(user, other_user)
1397
1398 conn =
1399 conn
1400 |> get("/api/v1/accounts/#{user.id}/following")
1401
1402 assert [] == json_response(conn, 200)
1403 end
1404
1405 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1406 user = insert(:user, %{info: %{hide_follows: true}})
1407 other_user = insert(:user)
1408 {:ok, user} = User.follow(user, other_user)
1409
1410 conn =
1411 conn
1412 |> assign(:user, user)
1413 |> get("/api/v1/accounts/#{user.id}/following")
1414
1415 refute [] == json_response(conn, 200)
1416 end
1417
1418 test "getting following, pagination", %{conn: conn} do
1419 user = insert(:user)
1420 following1 = insert(:user)
1421 following2 = insert(:user)
1422 following3 = insert(:user)
1423 {:ok, _} = User.follow(user, following1)
1424 {:ok, _} = User.follow(user, following2)
1425 {:ok, _} = User.follow(user, following3)
1426
1427 conn =
1428 conn
1429 |> assign(:user, user)
1430
1431 res_conn =
1432 conn
1433 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1434
1435 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1436 assert id3 == following3.id
1437 assert id2 == following2.id
1438
1439 res_conn =
1440 conn
1441 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1442
1443 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1444 assert id2 == following2.id
1445 assert id1 == following1.id
1446
1447 res_conn =
1448 conn
1449 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1450
1451 assert [%{"id" => id2}] = json_response(res_conn, 200)
1452 assert id2 == following2.id
1453
1454 assert [link_header] = get_resp_header(res_conn, "link")
1455 assert link_header =~ ~r/since_id=#{following2.id}/
1456 assert link_header =~ ~r/max_id=#{following2.id}/
1457 end
1458
1459 test "following / unfollowing a user", %{conn: conn} do
1460 user = insert(:user)
1461 other_user = insert(:user)
1462
1463 conn =
1464 conn
1465 |> assign(:user, user)
1466 |> post("/api/v1/accounts/#{other_user.id}/follow")
1467
1468 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1469
1470 user = Repo.get(User, user.id)
1471
1472 conn =
1473 build_conn()
1474 |> assign(:user, user)
1475 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1476
1477 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1478
1479 user = Repo.get(User, user.id)
1480
1481 conn =
1482 build_conn()
1483 |> assign(:user, user)
1484 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1485
1486 assert %{"id" => id} = json_response(conn, 200)
1487 assert id == to_string(other_user.id)
1488 end
1489
1490 test "muting / unmuting a user", %{conn: conn} do
1491 user = insert(:user)
1492 other_user = insert(:user)
1493
1494 conn =
1495 conn
1496 |> assign(:user, user)
1497 |> post("/api/v1/accounts/#{other_user.id}/mute")
1498
1499 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1500
1501 user = Repo.get(User, user.id)
1502
1503 conn =
1504 build_conn()
1505 |> assign(:user, user)
1506 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1507
1508 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1509 end
1510
1511 test "getting a list of mutes", %{conn: conn} do
1512 user = insert(:user)
1513 other_user = insert(:user)
1514
1515 {:ok, user} = User.mute(user, other_user)
1516
1517 conn =
1518 conn
1519 |> assign(:user, user)
1520 |> get("/api/v1/mutes")
1521
1522 other_user_id = to_string(other_user.id)
1523 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1524 end
1525
1526 test "blocking / unblocking a user", %{conn: conn} do
1527 user = insert(:user)
1528 other_user = insert(:user)
1529
1530 conn =
1531 conn
1532 |> assign(:user, user)
1533 |> post("/api/v1/accounts/#{other_user.id}/block")
1534
1535 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1536
1537 user = Repo.get(User, user.id)
1538
1539 conn =
1540 build_conn()
1541 |> assign(:user, user)
1542 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1543
1544 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1545 end
1546
1547 test "getting a list of blocks", %{conn: conn} do
1548 user = insert(:user)
1549 other_user = insert(:user)
1550
1551 {:ok, user} = User.block(user, other_user)
1552
1553 conn =
1554 conn
1555 |> assign(:user, user)
1556 |> get("/api/v1/blocks")
1557
1558 other_user_id = to_string(other_user.id)
1559 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1560 end
1561
1562 test "blocking / unblocking a domain", %{conn: conn} do
1563 user = insert(:user)
1564 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1565
1566 conn =
1567 conn
1568 |> assign(:user, user)
1569 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1570
1571 assert %{} = json_response(conn, 200)
1572 user = User.get_cached_by_ap_id(user.ap_id)
1573 assert User.blocks?(user, other_user)
1574
1575 conn =
1576 build_conn()
1577 |> assign(:user, user)
1578 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1579
1580 assert %{} = json_response(conn, 200)
1581 user = User.get_cached_by_ap_id(user.ap_id)
1582 refute User.blocks?(user, other_user)
1583 end
1584
1585 test "getting a list of domain blocks", %{conn: conn} do
1586 user = insert(:user)
1587
1588 {:ok, user} = User.block_domain(user, "bad.site")
1589 {:ok, user} = User.block_domain(user, "even.worse.site")
1590
1591 conn =
1592 conn
1593 |> assign(:user, user)
1594 |> get("/api/v1/domain_blocks")
1595
1596 domain_blocks = json_response(conn, 200)
1597
1598 assert "bad.site" in domain_blocks
1599 assert "even.worse.site" in domain_blocks
1600 end
1601
1602 test "unimplemented follow_requests, blocks, domain blocks" do
1603 user = insert(:user)
1604
1605 ["blocks", "domain_blocks", "follow_requests"]
1606 |> Enum.each(fn endpoint ->
1607 conn =
1608 build_conn()
1609 |> assign(:user, user)
1610 |> get("/api/v1/#{endpoint}")
1611
1612 assert [] = json_response(conn, 200)
1613 end)
1614 end
1615
1616 test "account search", %{conn: conn} do
1617 user = insert(:user)
1618 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1619 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1620
1621 results =
1622 conn
1623 |> assign(:user, user)
1624 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1625 |> json_response(200)
1626
1627 result_ids = for result <- results, do: result["acct"]
1628
1629 assert user_two.nickname in result_ids
1630 assert user_three.nickname in result_ids
1631
1632 results =
1633 conn
1634 |> assign(:user, user)
1635 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1636 |> json_response(200)
1637
1638 result_ids = for result <- results, do: result["acct"]
1639
1640 assert user_three.nickname in result_ids
1641 end
1642
1643 test "search", %{conn: conn} do
1644 user = insert(:user)
1645 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1646 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1647
1648 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1649
1650 {:ok, _activity} =
1651 CommonAPI.post(user, %{
1652 "status" => "This is about 2hu, but private",
1653 "visibility" => "private"
1654 })
1655
1656 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1657
1658 conn =
1659 conn
1660 |> get("/api/v1/search", %{"q" => "2hu"})
1661
1662 assert results = json_response(conn, 200)
1663
1664 [account | _] = results["accounts"]
1665 assert account["id"] == to_string(user_three.id)
1666
1667 assert results["hashtags"] == []
1668
1669 [status] = results["statuses"]
1670 assert status["id"] == to_string(activity.id)
1671 end
1672
1673 test "search fetches remote statuses", %{conn: conn} do
1674 capture_log(fn ->
1675 conn =
1676 conn
1677 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1678
1679 assert results = json_response(conn, 200)
1680
1681 [status] = results["statuses"]
1682 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1683 end)
1684 end
1685
1686 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1687 {:ok, activity} =
1688 CommonAPI.post(insert(:user), %{
1689 "status" => "This is about 2hu, but private",
1690 "visibility" => "private"
1691 })
1692
1693 capture_log(fn ->
1694 conn =
1695 conn
1696 |> get("/api/v1/search", %{"q" => activity.data["object"]["id"]})
1697
1698 assert results = json_response(conn, 200)
1699
1700 [] = results["statuses"]
1701 end)
1702 end
1703
1704 test "search fetches remote accounts", %{conn: conn} do
1705 conn =
1706 conn
1707 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1708
1709 assert results = json_response(conn, 200)
1710 [account] = results["accounts"]
1711 assert account["acct"] == "shp@social.heldscal.la"
1712 end
1713
1714 test "returns the favorites of a user", %{conn: conn} do
1715 user = insert(:user)
1716 other_user = insert(:user)
1717
1718 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1719 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1720
1721 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1722
1723 first_conn =
1724 conn
1725 |> assign(:user, user)
1726 |> get("/api/v1/favourites")
1727
1728 assert [status] = json_response(first_conn, 200)
1729 assert status["id"] == to_string(activity.id)
1730
1731 assert [{"link", _link_header}] =
1732 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1733
1734 # Honours query params
1735 {:ok, second_activity} =
1736 CommonAPI.post(other_user, %{
1737 "status" =>
1738 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1739 })
1740
1741 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1742
1743 last_like = status["id"]
1744
1745 second_conn =
1746 conn
1747 |> assign(:user, user)
1748 |> get("/api/v1/favourites?since_id=#{last_like}")
1749
1750 assert [second_status] = json_response(second_conn, 200)
1751 assert second_status["id"] == to_string(second_activity.id)
1752
1753 third_conn =
1754 conn
1755 |> assign(:user, user)
1756 |> get("/api/v1/favourites?limit=0")
1757
1758 assert [] = json_response(third_conn, 200)
1759 end
1760
1761 describe "updating credentials" do
1762 test "updates the user's bio", %{conn: conn} do
1763 user = insert(:user)
1764 user2 = insert(:user)
1765
1766 conn =
1767 conn
1768 |> assign(:user, user)
1769 |> patch("/api/v1/accounts/update_credentials", %{
1770 "note" => "I drink #cofe with @#{user2.nickname}"
1771 })
1772
1773 assert user = json_response(conn, 200)
1774
1775 assert user["note"] ==
1776 ~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=") <>
1777 user2.id <>
1778 ~s(" class="u-url mention" href=") <>
1779 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
1780 end
1781
1782 test "updates the user's locking status", %{conn: conn} do
1783 user = insert(:user)
1784
1785 conn =
1786 conn
1787 |> assign(:user, user)
1788 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
1789
1790 assert user = json_response(conn, 200)
1791 assert user["locked"] == true
1792 end
1793
1794 test "updates the user's name", %{conn: conn} do
1795 user = insert(:user)
1796
1797 conn =
1798 conn
1799 |> assign(:user, user)
1800 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
1801
1802 assert user = json_response(conn, 200)
1803 assert user["display_name"] == "markorepairs"
1804 end
1805
1806 test "updates the user's avatar", %{conn: conn} do
1807 user = insert(:user)
1808
1809 new_avatar = %Plug.Upload{
1810 content_type: "image/jpg",
1811 path: Path.absname("test/fixtures/image.jpg"),
1812 filename: "an_image.jpg"
1813 }
1814
1815 conn =
1816 conn
1817 |> assign(:user, user)
1818 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
1819
1820 assert user_response = json_response(conn, 200)
1821 assert user_response["avatar"] != User.avatar_url(user)
1822 end
1823
1824 test "updates the user's banner", %{conn: conn} do
1825 user = insert(:user)
1826
1827 new_header = %Plug.Upload{
1828 content_type: "image/jpg",
1829 path: Path.absname("test/fixtures/image.jpg"),
1830 filename: "an_image.jpg"
1831 }
1832
1833 conn =
1834 conn
1835 |> assign(:user, user)
1836 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
1837
1838 assert user_response = json_response(conn, 200)
1839 assert user_response["header"] != User.banner_url(user)
1840 end
1841
1842 test "requires 'write' permission", %{conn: conn} do
1843 token1 = insert(:oauth_token, scopes: ["read"])
1844 token2 = insert(:oauth_token, scopes: ["write", "follow"])
1845
1846 for token <- [token1, token2] do
1847 conn =
1848 conn
1849 |> put_req_header("authorization", "Bearer #{token.token}")
1850 |> patch("/api/v1/accounts/update_credentials", %{})
1851
1852 if token == token1 do
1853 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
1854 else
1855 assert json_response(conn, 200)
1856 end
1857 end
1858 end
1859 end
1860
1861 test "get instance information", %{conn: conn} do
1862 user = insert(:user, %{local: true})
1863
1864 user2 = insert(:user, %{local: true})
1865 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1866
1867 insert(:user, %{local: false, nickname: "u@peer1.com"})
1868 insert(:user, %{local: false, nickname: "u@peer2.com"})
1869
1870 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
1871
1872 # Stats should count users with missing or nil `info.deactivated` value
1873 user = Repo.get(User, user.id)
1874 info_change = Changeset.change(user.info, %{deactivated: nil})
1875
1876 {:ok, _user} =
1877 user
1878 |> Changeset.change()
1879 |> Changeset.put_embed(:info, info_change)
1880 |> User.update_and_set_cache()
1881
1882 Pleroma.Stats.update_stats()
1883
1884 conn = get(conn, "/api/v1/instance")
1885
1886 assert result = json_response(conn, 200)
1887
1888 stats = result["stats"]
1889
1890 assert stats
1891 assert stats["user_count"] == 1
1892 assert stats["status_count"] == 1
1893 assert stats["domain_count"] == 2
1894 end
1895
1896 test "get peers", %{conn: conn} do
1897 insert(:user, %{local: false, nickname: "u@peer1.com"})
1898 insert(:user, %{local: false, nickname: "u@peer2.com"})
1899
1900 Pleroma.Stats.update_stats()
1901
1902 conn = get(conn, "/api/v1/instance/peers")
1903
1904 assert result = json_response(conn, 200)
1905
1906 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1907 end
1908
1909 test "put settings", %{conn: conn} do
1910 user = insert(:user)
1911
1912 conn =
1913 conn
1914 |> assign(:user, user)
1915 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
1916
1917 assert _result = json_response(conn, 200)
1918
1919 user = User.get_cached_by_ap_id(user.ap_id)
1920 assert user.info.settings == %{"programming" => "socks"}
1921 end
1922
1923 describe "pinned statuses" do
1924 setup do
1925 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
1926
1927 user = insert(:user)
1928 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
1929
1930 [user: user, activity: activity]
1931 end
1932
1933 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
1934 {:ok, _} = CommonAPI.pin(activity.id, user)
1935
1936 result =
1937 conn
1938 |> assign(:user, user)
1939 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1940 |> json_response(200)
1941
1942 id_str = to_string(activity.id)
1943
1944 assert [%{"id" => ^id_str, "pinned" => true}] = result
1945 end
1946
1947 test "pin status", %{conn: conn, user: user, activity: activity} do
1948 id_str = to_string(activity.id)
1949
1950 assert %{"id" => ^id_str, "pinned" => true} =
1951 conn
1952 |> assign(:user, user)
1953 |> post("/api/v1/statuses/#{activity.id}/pin")
1954 |> json_response(200)
1955
1956 assert [%{"id" => ^id_str, "pinned" => true}] =
1957 conn
1958 |> assign(:user, user)
1959 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1960 |> json_response(200)
1961 end
1962
1963 test "unpin status", %{conn: conn, user: user, activity: activity} do
1964 {:ok, _} = CommonAPI.pin(activity.id, user)
1965
1966 id_str = to_string(activity.id)
1967 user = refresh_record(user)
1968
1969 assert %{"id" => ^id_str, "pinned" => false} =
1970 conn
1971 |> assign(:user, user)
1972 |> post("/api/v1/statuses/#{activity.id}/unpin")
1973 |> json_response(200)
1974
1975 assert [] =
1976 conn
1977 |> assign(:user, user)
1978 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1979 |> json_response(200)
1980 end
1981
1982 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
1983 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
1984
1985 id_str_one = to_string(activity_one.id)
1986
1987 assert %{"id" => ^id_str_one, "pinned" => true} =
1988 conn
1989 |> assign(:user, user)
1990 |> post("/api/v1/statuses/#{id_str_one}/pin")
1991 |> json_response(200)
1992
1993 user = refresh_record(user)
1994
1995 assert %{"error" => "You have already pinned the maximum number of statuses"} =
1996 conn
1997 |> assign(:user, user)
1998 |> post("/api/v1/statuses/#{activity_two.id}/pin")
1999 |> json_response(400)
2000 end
2001
2002 test "Status rich-media Card", %{conn: conn, user: user} do
2003 Pleroma.Config.put([:rich_media, :enabled], true)
2004 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2005
2006 response =
2007 conn
2008 |> get("/api/v1/statuses/#{activity.id}/card")
2009 |> json_response(200)
2010
2011 assert response == %{
2012 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2013 "provider_name" => "www.imdb.com",
2014 "provider_url" => "http://www.imdb.com",
2015 "title" => "The Rock",
2016 "type" => "link",
2017 "url" => "http://www.imdb.com/title/tt0117500/",
2018 "description" => nil,
2019 "pleroma" => %{
2020 "opengraph" => %{
2021 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2022 "title" => "The Rock",
2023 "type" => "video.movie",
2024 "url" => "http://www.imdb.com/title/tt0117500/"
2025 }
2026 }
2027 }
2028
2029 # works with private posts
2030 {:ok, activity} =
2031 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2032
2033 response_two =
2034 conn
2035 |> assign(:user, user)
2036 |> get("/api/v1/statuses/#{activity.id}/card")
2037 |> json_response(200)
2038
2039 assert response_two == response
2040
2041 Pleroma.Config.put([:rich_media, :enabled], false)
2042 end
2043 end
2044
2045 test "bookmarks" do
2046 user = insert(:user)
2047 for_user = insert(:user)
2048
2049 {:ok, activity1} =
2050 CommonAPI.post(user, %{
2051 "status" => "heweoo?"
2052 })
2053
2054 {:ok, activity2} =
2055 CommonAPI.post(user, %{
2056 "status" => "heweoo!"
2057 })
2058
2059 response1 =
2060 build_conn()
2061 |> assign(:user, for_user)
2062 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2063
2064 assert json_response(response1, 200)["bookmarked"] == true
2065
2066 response2 =
2067 build_conn()
2068 |> assign(:user, for_user)
2069 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2070
2071 assert json_response(response2, 200)["bookmarked"] == true
2072
2073 bookmarks =
2074 build_conn()
2075 |> assign(:user, for_user)
2076 |> get("/api/v1/bookmarks")
2077
2078 assert [json_response(response2, 200), json_response(response1, 200)] ==
2079 json_response(bookmarks, 200)
2080
2081 response1 =
2082 build_conn()
2083 |> assign(:user, for_user)
2084 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2085
2086 assert json_response(response1, 200)["bookmarked"] == false
2087
2088 bookmarks =
2089 build_conn()
2090 |> assign(:user, for_user)
2091 |> get("/api/v1/bookmarks")
2092
2093 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2094 end
2095
2096 describe "conversation muting" do
2097 setup do
2098 user = insert(:user)
2099 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2100
2101 [user: user, activity: activity]
2102 end
2103
2104 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2105 id_str = to_string(activity.id)
2106
2107 assert %{"id" => ^id_str, "muted" => true} =
2108 conn
2109 |> assign(:user, user)
2110 |> post("/api/v1/statuses/#{activity.id}/mute")
2111 |> json_response(200)
2112 end
2113
2114 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2115 {:ok, _} = CommonAPI.add_mute(user, activity)
2116
2117 id_str = to_string(activity.id)
2118 user = refresh_record(user)
2119
2120 assert %{"id" => ^id_str, "muted" => false} =
2121 conn
2122 |> assign(:user, user)
2123 |> post("/api/v1/statuses/#{activity.id}/unmute")
2124 |> json_response(200)
2125 end
2126 end
2127
2128 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2129 user = insert(:user)
2130
2131 get_old_flavour =
2132 conn
2133 |> assign(:user, user)
2134 |> get("/api/v1/pleroma/flavour")
2135
2136 assert "glitch" == json_response(get_old_flavour, 200)
2137
2138 set_flavour =
2139 conn
2140 |> assign(:user, user)
2141 |> post("/api/v1/pleroma/flavour/vanilla")
2142
2143 assert "vanilla" == json_response(set_flavour, 200)
2144
2145 get_new_flavour =
2146 conn
2147 |> assign(:user, user)
2148 |> post("/api/v1/pleroma/flavour/vanilla")
2149
2150 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2151 end
2152
2153 describe "reports" do
2154 setup do
2155 reporter = insert(:user)
2156 target_user = insert(:user)
2157
2158 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2159
2160 [reporter: reporter, target_user: target_user, activity: activity]
2161 end
2162
2163 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2164 assert %{"action_taken" => false, "id" => _} =
2165 conn
2166 |> assign(:user, reporter)
2167 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2168 |> json_response(200)
2169 end
2170
2171 test "submit a report with statuses and comment", %{
2172 conn: conn,
2173 reporter: reporter,
2174 target_user: target_user,
2175 activity: activity
2176 } do
2177 assert %{"action_taken" => false, "id" => _} =
2178 conn
2179 |> assign(:user, reporter)
2180 |> post("/api/v1/reports", %{
2181 "account_id" => target_user.id,
2182 "status_ids" => [activity.id],
2183 "comment" => "bad status!"
2184 })
2185 |> json_response(200)
2186 end
2187
2188 test "account_id is required", %{
2189 conn: conn,
2190 reporter: reporter,
2191 activity: activity
2192 } do
2193 assert %{"error" => "Valid `account_id` required"} =
2194 conn
2195 |> assign(:user, reporter)
2196 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2197 |> json_response(400)
2198 end
2199
2200 test "comment must be up to the size specified in the config", %{
2201 conn: conn,
2202 reporter: reporter,
2203 target_user: target_user
2204 } do
2205 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2206 comment = String.pad_trailing("a", max_size + 1, "a")
2207
2208 error = %{"error" => "Comment must be up to #{max_size} characters"}
2209
2210 assert ^error =
2211 conn
2212 |> assign(:user, reporter)
2213 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2214 |> json_response(400)
2215 end
2216 end
2217
2218 describe "link headers" do
2219 test "preserves parameters in link headers", %{conn: conn} do
2220 user = insert(:user)
2221 other_user = insert(:user)
2222
2223 {:ok, activity1} =
2224 CommonAPI.post(other_user, %{
2225 "status" => "hi @#{user.nickname}",
2226 "visibility" => "public"
2227 })
2228
2229 {:ok, activity2} =
2230 CommonAPI.post(other_user, %{
2231 "status" => "hi @#{user.nickname}",
2232 "visibility" => "public"
2233 })
2234
2235 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2236 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2237
2238 conn =
2239 conn
2240 |> assign(:user, user)
2241 |> get("/api/v1/notifications", %{media_only: true})
2242
2243 assert [link_header] = get_resp_header(conn, "link")
2244 assert link_header =~ ~r/media_only=true/
2245 assert link_header =~ ~r/since_id=#{notification2.id}/
2246 assert link_header =~ ~r/max_id=#{notification1.id}/
2247 end
2248 end
2249 end