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