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