Merge branch 'captcha' into 'develop'
[akkoma] / test / web / mastodon_api / mastodon_api_controller_test.exs
1 defmodule Pleroma.Web.MastodonAPI.MastodonAPIControllerTest do
2 use Pleroma.Web.ConnCase
3
4 alias Pleroma.Web.TwitterAPI.TwitterAPI
5 alias Pleroma.{Repo, User, Object, Activity, Notification}
6 alias Pleroma.Web.{OStatus, CommonAPI}
7 alias Pleroma.Web.ActivityPub.ActivityPub
8 alias Pleroma.Web.MastodonAPI.FilterView
9 import Pleroma.Factory
10 import ExUnit.CaptureLog
11 import Tesla.Mock
12
13 setup do
14 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
15 :ok
16 end
17
18 test "the home timeline", %{conn: conn} do
19 user = insert(:user)
20 following = insert(:user)
21
22 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
23
24 conn =
25 conn
26 |> assign(:user, user)
27 |> get("/api/v1/timelines/home")
28
29 assert length(json_response(conn, 200)) == 0
30
31 {:ok, user} = User.follow(user, following)
32
33 conn =
34 build_conn()
35 |> assign(:user, user)
36 |> get("/api/v1/timelines/home")
37
38 assert [%{"content" => "test"}] = json_response(conn, 200)
39 end
40
41 test "the public timeline", %{conn: conn} do
42 following = insert(:user)
43
44 capture_log(fn ->
45 {:ok, _activity} = TwitterAPI.create_status(following, %{"status" => "test"})
46
47 {:ok, [_activity]} =
48 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
49
50 conn =
51 conn
52 |> get("/api/v1/timelines/public", %{"local" => "False"})
53
54 assert length(json_response(conn, 200)) == 2
55
56 conn =
57 build_conn()
58 |> get("/api/v1/timelines/public", %{"local" => "True"})
59
60 assert [%{"content" => "test"}] = json_response(conn, 200)
61
62 conn =
63 build_conn()
64 |> get("/api/v1/timelines/public", %{"local" => "1"})
65
66 assert [%{"content" => "test"}] = json_response(conn, 200)
67 end)
68 end
69
70 test "posting a status", %{conn: conn} do
71 user = insert(:user)
72
73 idempotency_key = "Pikachu rocks!"
74
75 conn_one =
76 conn
77 |> assign(:user, user)
78 |> put_req_header("idempotency-key", idempotency_key)
79 |> post("/api/v1/statuses", %{
80 "status" => "cofe",
81 "spoiler_text" => "2hu",
82 "sensitive" => "false"
83 })
84
85 {:ok, ttl} = Cachex.ttl(:idempotency_cache, idempotency_key)
86 # Six hours
87 assert ttl > :timer.seconds(6 * 60 * 60 - 1)
88
89 assert %{"content" => "cofe", "id" => id, "spoiler_text" => "2hu", "sensitive" => false} =
90 json_response(conn_one, 200)
91
92 assert Repo.get(Activity, id)
93
94 conn_two =
95 conn
96 |> assign(:user, user)
97 |> put_req_header("idempotency-key", idempotency_key)
98 |> post("/api/v1/statuses", %{
99 "status" => "cofe",
100 "spoiler_text" => "2hu",
101 "sensitive" => "false"
102 })
103
104 assert %{"id" => second_id} = json_response(conn_two, 200)
105
106 assert id == second_id
107
108 conn_three =
109 conn
110 |> assign(:user, user)
111 |> post("/api/v1/statuses", %{
112 "status" => "cofe",
113 "spoiler_text" => "2hu",
114 "sensitive" => "false"
115 })
116
117 assert %{"id" => third_id} = json_response(conn_three, 200)
118
119 refute id == third_id
120 end
121
122 test "posting a sensitive status", %{conn: conn} do
123 user = insert(:user)
124
125 conn =
126 conn
127 |> assign(:user, user)
128 |> post("/api/v1/statuses", %{"status" => "cofe", "sensitive" => true})
129
130 assert %{"content" => "cofe", "id" => id, "sensitive" => true} = json_response(conn, 200)
131 assert Repo.get(Activity, id)
132 end
133
134 test "posting a direct status", %{conn: conn} do
135 user1 = insert(:user)
136 user2 = insert(:user)
137 content = "direct cofe @#{user2.nickname}"
138
139 conn =
140 conn
141 |> assign(:user, user1)
142 |> post("api/v1/statuses", %{"status" => content, "visibility" => "direct"})
143
144 assert %{"id" => id, "visibility" => "direct"} = json_response(conn, 200)
145 assert activity = Repo.get(Activity, id)
146 assert activity.recipients == [user2.ap_id]
147 assert activity.data["to"] == [user2.ap_id]
148 assert activity.data["cc"] == []
149 end
150
151 test "direct timeline", %{conn: conn} do
152 user_one = insert(:user)
153 user_two = insert(:user)
154
155 {:ok, user_two} = User.follow(user_two, user_one)
156
157 {:ok, direct} =
158 CommonAPI.post(user_one, %{
159 "status" => "Hi @#{user_two.nickname}!",
160 "visibility" => "direct"
161 })
162
163 {:ok, _follower_only} =
164 CommonAPI.post(user_one, %{
165 "status" => "Hi @#{user_two.nickname}!",
166 "visibility" => "private"
167 })
168
169 # Only direct should be visible here
170 res_conn =
171 conn
172 |> assign(:user, user_two)
173 |> get("api/v1/timelines/direct")
174
175 [status] = json_response(res_conn, 200)
176
177 assert %{"visibility" => "direct"} = status
178 assert status["url"] != direct.data["id"]
179
180 # Both should be visible here
181 res_conn =
182 conn
183 |> assign(:user, user_two)
184 |> get("api/v1/timelines/home")
185
186 [_s1, _s2] = json_response(res_conn, 200)
187
188 # Test pagination
189 Enum.each(1..20, fn _ ->
190 {:ok, _} =
191 CommonAPI.post(user_one, %{
192 "status" => "Hi @#{user_two.nickname}!",
193 "visibility" => "direct"
194 })
195 end)
196
197 res_conn =
198 conn
199 |> assign(:user, user_two)
200 |> get("api/v1/timelines/direct")
201
202 statuses = json_response(res_conn, 200)
203 assert length(statuses) == 20
204
205 res_conn =
206 conn
207 |> assign(:user, user_two)
208 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
209
210 [status] = json_response(res_conn, 200)
211
212 assert status["url"] != direct.data["id"]
213 end
214
215 test "replying to a status", %{conn: conn} do
216 user = insert(:user)
217
218 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
219
220 conn =
221 conn
222 |> assign(:user, user)
223 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
224
225 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
226
227 activity = Repo.get(Activity, id)
228
229 assert activity.data["context"] == replied_to.data["context"]
230 assert activity.data["object"]["inReplyToStatusId"] == replied_to.id
231 end
232
233 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
234 user = insert(:user)
235
236 conn =
237 conn
238 |> assign(:user, user)
239 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
240
241 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
242
243 activity = Repo.get(Activity, id)
244
245 assert activity
246 end
247
248 test "verify_credentials", %{conn: conn} do
249 user = insert(:user)
250
251 conn =
252 conn
253 |> assign(:user, user)
254 |> get("/api/v1/accounts/verify_credentials")
255
256 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
257 assert id == to_string(user.id)
258 end
259
260 test "verify_credentials default scope unlisted", %{conn: conn} do
261 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
262
263 conn =
264 conn
265 |> assign(:user, user)
266 |> get("/api/v1/accounts/verify_credentials")
267
268 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
269 assert id == to_string(user.id)
270 end
271
272 test "get a status", %{conn: conn} do
273 activity = insert(:note_activity)
274
275 conn =
276 conn
277 |> get("/api/v1/statuses/#{activity.id}")
278
279 assert %{"id" => id} = json_response(conn, 200)
280 assert id == to_string(activity.id)
281 end
282
283 describe "deleting a status" do
284 test "when you created it", %{conn: conn} do
285 activity = insert(:note_activity)
286 author = User.get_by_ap_id(activity.data["actor"])
287
288 conn =
289 conn
290 |> assign(:user, author)
291 |> delete("/api/v1/statuses/#{activity.id}")
292
293 assert %{} = json_response(conn, 200)
294
295 assert Repo.get(Activity, activity.id) == nil
296 end
297
298 test "when you didn't create it", %{conn: conn} do
299 activity = insert(:note_activity)
300 user = insert(:user)
301
302 conn =
303 conn
304 |> assign(:user, user)
305 |> delete("/api/v1/statuses/#{activity.id}")
306
307 assert %{"error" => _} = json_response(conn, 403)
308
309 assert Repo.get(Activity, activity.id) == activity
310 end
311 end
312
313 describe "filters" do
314 test "creating a filter", %{conn: conn} do
315 user = insert(:user)
316
317 filter = %Pleroma.Filter{
318 phrase: "knights",
319 context: ["home"]
320 }
321
322 conn =
323 conn
324 |> assign(:user, user)
325 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
326
327 assert response = json_response(conn, 200)
328 assert response["phrase"] == filter.phrase
329 assert response["context"] == filter.context
330 assert response["id"] != nil
331 assert response["id"] != ""
332 end
333
334 test "fetching a list of filters", %{conn: conn} do
335 user = insert(:user)
336
337 query_one = %Pleroma.Filter{
338 user_id: user.id,
339 filter_id: 1,
340 phrase: "knights",
341 context: ["home"]
342 }
343
344 query_two = %Pleroma.Filter{
345 user_id: user.id,
346 filter_id: 2,
347 phrase: "who",
348 context: ["home"]
349 }
350
351 {:ok, filter_one} = Pleroma.Filter.create(query_one)
352 {:ok, filter_two} = Pleroma.Filter.create(query_two)
353
354 response =
355 conn
356 |> assign(:user, user)
357 |> get("/api/v1/filters")
358 |> json_response(200)
359
360 assert response ==
361 render_json(
362 FilterView,
363 "filters.json",
364 filters: [filter_two, filter_one]
365 )
366 end
367
368 test "get a filter", %{conn: conn} do
369 user = insert(:user)
370
371 query = %Pleroma.Filter{
372 user_id: user.id,
373 filter_id: 2,
374 phrase: "knight",
375 context: ["home"]
376 }
377
378 {:ok, filter} = Pleroma.Filter.create(query)
379
380 conn =
381 conn
382 |> assign(:user, user)
383 |> get("/api/v1/filters/#{filter.filter_id}")
384
385 assert response = json_response(conn, 200)
386 end
387
388 test "update a filter", %{conn: conn} do
389 user = insert(:user)
390
391 query = %Pleroma.Filter{
392 user_id: user.id,
393 filter_id: 2,
394 phrase: "knight",
395 context: ["home"]
396 }
397
398 {:ok, _filter} = Pleroma.Filter.create(query)
399
400 new = %Pleroma.Filter{
401 phrase: "nii",
402 context: ["home"]
403 }
404
405 conn =
406 conn
407 |> assign(:user, user)
408 |> put("/api/v1/filters/#{query.filter_id}", %{
409 phrase: new.phrase,
410 context: new.context
411 })
412
413 assert response = json_response(conn, 200)
414 assert response["phrase"] == new.phrase
415 assert response["context"] == new.context
416 end
417
418 test "delete a filter", %{conn: conn} do
419 user = insert(:user)
420
421 query = %Pleroma.Filter{
422 user_id: user.id,
423 filter_id: 2,
424 phrase: "knight",
425 context: ["home"]
426 }
427
428 {:ok, filter} = Pleroma.Filter.create(query)
429
430 conn =
431 conn
432 |> assign(:user, user)
433 |> delete("/api/v1/filters/#{filter.filter_id}")
434
435 assert response = json_response(conn, 200)
436 assert response == %{}
437 end
438 end
439
440 describe "lists" do
441 test "creating a list", %{conn: conn} do
442 user = insert(:user)
443
444 conn =
445 conn
446 |> assign(:user, user)
447 |> post("/api/v1/lists", %{"title" => "cuties"})
448
449 assert %{"title" => title} = json_response(conn, 200)
450 assert title == "cuties"
451 end
452
453 test "adding users to a list", %{conn: conn} do
454 user = insert(:user)
455 other_user = insert(:user)
456 {:ok, list} = Pleroma.List.create("name", user)
457
458 conn =
459 conn
460 |> assign(:user, user)
461 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
462
463 assert %{} == json_response(conn, 200)
464 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
465 assert following == [other_user.follower_address]
466 end
467
468 test "removing users from a list", %{conn: conn} do
469 user = insert(:user)
470 other_user = insert(:user)
471 third_user = insert(:user)
472 {:ok, list} = Pleroma.List.create("name", user)
473 {:ok, list} = Pleroma.List.follow(list, other_user)
474 {:ok, list} = Pleroma.List.follow(list, third_user)
475
476 conn =
477 conn
478 |> assign(:user, user)
479 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
480
481 assert %{} == json_response(conn, 200)
482 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
483 assert following == [third_user.follower_address]
484 end
485
486 test "listing users in a list", %{conn: conn} do
487 user = insert(:user)
488 other_user = insert(:user)
489 {:ok, list} = Pleroma.List.create("name", user)
490 {:ok, list} = Pleroma.List.follow(list, other_user)
491
492 conn =
493 conn
494 |> assign(:user, user)
495 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
496
497 assert [%{"id" => id}] = json_response(conn, 200)
498 assert id == to_string(other_user.id)
499 end
500
501 test "retrieving a list", %{conn: conn} do
502 user = insert(:user)
503 {:ok, list} = Pleroma.List.create("name", user)
504
505 conn =
506 conn
507 |> assign(:user, user)
508 |> get("/api/v1/lists/#{list.id}")
509
510 assert %{"id" => id} = json_response(conn, 200)
511 assert id == to_string(list.id)
512 end
513
514 test "renaming a list", %{conn: conn} do
515 user = insert(:user)
516 {:ok, list} = Pleroma.List.create("name", user)
517
518 conn =
519 conn
520 |> assign(:user, user)
521 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
522
523 assert %{"title" => name} = json_response(conn, 200)
524 assert name == "newname"
525 end
526
527 test "deleting a list", %{conn: conn} do
528 user = insert(:user)
529 {:ok, list} = Pleroma.List.create("name", user)
530
531 conn =
532 conn
533 |> assign(:user, user)
534 |> delete("/api/v1/lists/#{list.id}")
535
536 assert %{} = json_response(conn, 200)
537 assert is_nil(Repo.get(Pleroma.List, list.id))
538 end
539
540 test "list timeline", %{conn: conn} do
541 user = insert(:user)
542 other_user = insert(:user)
543 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
544 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
545 {:ok, list} = Pleroma.List.create("name", user)
546 {:ok, list} = Pleroma.List.follow(list, other_user)
547
548 conn =
549 conn
550 |> assign(:user, user)
551 |> get("/api/v1/timelines/list/#{list.id}")
552
553 assert [%{"id" => id}] = json_response(conn, 200)
554
555 assert id == to_string(activity_two.id)
556 end
557
558 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
559 user = insert(:user)
560 other_user = insert(:user)
561 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
562
563 {:ok, _activity_two} =
564 TwitterAPI.create_status(other_user, %{
565 "status" => "Marisa is cute.",
566 "visibility" => "private"
567 })
568
569 {:ok, list} = Pleroma.List.create("name", user)
570 {:ok, list} = Pleroma.List.follow(list, other_user)
571
572 conn =
573 conn
574 |> assign(:user, user)
575 |> get("/api/v1/timelines/list/#{list.id}")
576
577 assert [%{"id" => id}] = json_response(conn, 200)
578
579 assert id == to_string(activity_one.id)
580 end
581 end
582
583 describe "notifications" do
584 test "list of notifications", %{conn: conn} do
585 user = insert(:user)
586 other_user = insert(:user)
587
588 {:ok, activity} =
589 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
590
591 {:ok, [_notification]} = Notification.create_notifications(activity)
592
593 conn =
594 conn
595 |> assign(:user, user)
596 |> get("/api/v1/notifications")
597
598 expected_response =
599 "hi <span><a data-user=\"#{user.id}\" href=\"#{user.ap_id}\">@<span>#{user.nickname}</span></a></span>"
600
601 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
602 assert response == expected_response
603 end
604
605 test "getting a single notification", %{conn: conn} do
606 user = insert(:user)
607 other_user = insert(:user)
608
609 {:ok, activity} =
610 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
611
612 {:ok, [notification]} = Notification.create_notifications(activity)
613
614 conn =
615 conn
616 |> assign(:user, user)
617 |> get("/api/v1/notifications/#{notification.id}")
618
619 expected_response =
620 "hi <span><a data-user=\"#{user.id}\" href=\"#{user.ap_id}\">@<span>#{user.nickname}</span></a></span>"
621
622 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
623 assert response == expected_response
624 end
625
626 test "dismissing a single notification", %{conn: conn} do
627 user = insert(:user)
628 other_user = insert(:user)
629
630 {:ok, activity} =
631 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
632
633 {:ok, [notification]} = Notification.create_notifications(activity)
634
635 conn =
636 conn
637 |> assign(:user, user)
638 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
639
640 assert %{} = json_response(conn, 200)
641 end
642
643 test "clearing all notifications", %{conn: conn} do
644 user = insert(:user)
645 other_user = insert(:user)
646
647 {:ok, activity} =
648 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
649
650 {:ok, [_notification]} = Notification.create_notifications(activity)
651
652 conn =
653 conn
654 |> assign(:user, user)
655 |> post("/api/v1/notifications/clear")
656
657 assert %{} = json_response(conn, 200)
658
659 conn =
660 build_conn()
661 |> assign(:user, user)
662 |> get("/api/v1/notifications")
663
664 assert all = json_response(conn, 200)
665 assert all == []
666 end
667 end
668
669 describe "reblogging" do
670 test "reblogs and returns the reblogged status", %{conn: conn} do
671 activity = insert(:note_activity)
672 user = insert(:user)
673
674 conn =
675 conn
676 |> assign(:user, user)
677 |> post("/api/v1/statuses/#{activity.id}/reblog")
678
679 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
680 json_response(conn, 200)
681
682 assert to_string(activity.id) == id
683 end
684 end
685
686 describe "unreblogging" do
687 test "unreblogs and returns the unreblogged status", %{conn: conn} do
688 activity = insert(:note_activity)
689 user = insert(:user)
690
691 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
692
693 conn =
694 conn
695 |> assign(:user, user)
696 |> post("/api/v1/statuses/#{activity.id}/unreblog")
697
698 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
699
700 assert to_string(activity.id) == id
701 end
702 end
703
704 describe "favoriting" do
705 test "favs a status and returns it", %{conn: conn} do
706 activity = insert(:note_activity)
707 user = insert(:user)
708
709 conn =
710 conn
711 |> assign(:user, user)
712 |> post("/api/v1/statuses/#{activity.id}/favourite")
713
714 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
715 json_response(conn, 200)
716
717 assert to_string(activity.id) == id
718 end
719
720 test "returns 500 for a wrong id", %{conn: conn} do
721 user = insert(:user)
722
723 resp =
724 conn
725 |> assign(:user, user)
726 |> post("/api/v1/statuses/1/favourite")
727 |> json_response(500)
728
729 assert resp == "Something went wrong"
730 end
731 end
732
733 describe "unfavoriting" do
734 test "unfavorites a status and returns it", %{conn: conn} do
735 activity = insert(:note_activity)
736 user = insert(:user)
737
738 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
739
740 conn =
741 conn
742 |> assign(:user, user)
743 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
744
745 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
746 json_response(conn, 200)
747
748 assert to_string(activity.id) == id
749 end
750 end
751
752 describe "user timelines" do
753 test "gets a users statuses", %{conn: conn} do
754 user_one = insert(:user)
755 user_two = insert(:user)
756 user_three = insert(:user)
757
758 {:ok, user_three} = User.follow(user_three, user_one)
759
760 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
761
762 {:ok, direct_activity} =
763 CommonAPI.post(user_one, %{
764 "status" => "Hi, @#{user_two.nickname}.",
765 "visibility" => "direct"
766 })
767
768 {:ok, private_activity} =
769 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
770
771 resp =
772 conn
773 |> get("/api/v1/accounts/#{user_one.id}/statuses")
774
775 assert [%{"id" => id}] = json_response(resp, 200)
776 assert id == to_string(activity.id)
777
778 resp =
779 conn
780 |> assign(:user, user_two)
781 |> get("/api/v1/accounts/#{user_one.id}/statuses")
782
783 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
784 assert id_one == to_string(direct_activity.id)
785 assert id_two == to_string(activity.id)
786
787 resp =
788 conn
789 |> assign(:user, user_three)
790 |> get("/api/v1/accounts/#{user_one.id}/statuses")
791
792 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
793 assert id_one == to_string(private_activity.id)
794 assert id_two == to_string(activity.id)
795 end
796
797 test "unimplemented pinned statuses feature", %{conn: conn} do
798 note = insert(:note_activity)
799 user = User.get_by_ap_id(note.data["actor"])
800
801 conn =
802 conn
803 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
804
805 assert json_response(conn, 200) == []
806 end
807
808 test "gets an users media", %{conn: conn} do
809 note = insert(:note_activity)
810 user = User.get_by_ap_id(note.data["actor"])
811
812 file = %Plug.Upload{
813 content_type: "image/jpg",
814 path: Path.absname("test/fixtures/image.jpg"),
815 filename: "an_image.jpg"
816 }
817
818 media =
819 TwitterAPI.upload(file, user, "json")
820 |> Poison.decode!()
821
822 {:ok, image_post} =
823 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
824
825 conn =
826 conn
827 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
828
829 assert [%{"id" => id}] = json_response(conn, 200)
830 assert id == to_string(image_post.id)
831
832 conn =
833 build_conn()
834 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
835
836 assert [%{"id" => id}] = json_response(conn, 200)
837 assert id == to_string(image_post.id)
838 end
839 end
840
841 describe "user relationships" do
842 test "returns the relationships for the current user", %{conn: conn} do
843 user = insert(:user)
844 other_user = insert(:user)
845 {:ok, user} = User.follow(user, other_user)
846
847 conn =
848 conn
849 |> assign(:user, user)
850 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
851
852 assert [relationship] = json_response(conn, 200)
853
854 assert to_string(other_user.id) == relationship["id"]
855 end
856 end
857
858 describe "locked accounts" do
859 test "/api/v1/follow_requests works" do
860 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
861 other_user = insert(:user)
862
863 {:ok, _activity} = ActivityPub.follow(other_user, user)
864
865 user = Repo.get(User, user.id)
866 other_user = Repo.get(User, other_user.id)
867
868 assert User.following?(other_user, user) == false
869
870 conn =
871 build_conn()
872 |> assign(:user, user)
873 |> get("/api/v1/follow_requests")
874
875 assert [relationship] = json_response(conn, 200)
876 assert to_string(other_user.id) == relationship["id"]
877 end
878
879 test "/api/v1/follow_requests/:id/authorize works" do
880 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
881 other_user = insert(:user)
882
883 {:ok, _activity} = ActivityPub.follow(other_user, user)
884
885 user = Repo.get(User, user.id)
886 other_user = Repo.get(User, other_user.id)
887
888 assert User.following?(other_user, user) == false
889
890 conn =
891 build_conn()
892 |> assign(:user, user)
893 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
894
895 assert relationship = json_response(conn, 200)
896 assert to_string(other_user.id) == relationship["id"]
897
898 user = Repo.get(User, user.id)
899 other_user = Repo.get(User, other_user.id)
900
901 assert User.following?(other_user, user) == true
902 end
903
904 test "verify_credentials", %{conn: conn} do
905 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
906
907 conn =
908 conn
909 |> assign(:user, user)
910 |> get("/api/v1/accounts/verify_credentials")
911
912 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
913 assert id == to_string(user.id)
914 end
915
916 test "/api/v1/follow_requests/:id/reject works" do
917 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
918 other_user = insert(:user)
919
920 {:ok, _activity} = ActivityPub.follow(other_user, user)
921
922 conn =
923 build_conn()
924 |> assign(:user, user)
925 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
926
927 assert relationship = json_response(conn, 200)
928 assert to_string(other_user.id) == relationship["id"]
929
930 user = Repo.get(User, user.id)
931 other_user = Repo.get(User, other_user.id)
932
933 assert User.following?(other_user, user) == false
934 end
935 end
936
937 test "account fetching", %{conn: conn} do
938 user = insert(:user)
939
940 conn =
941 conn
942 |> get("/api/v1/accounts/#{user.id}")
943
944 assert %{"id" => id} = json_response(conn, 200)
945 assert id == to_string(user.id)
946
947 conn =
948 build_conn()
949 |> get("/api/v1/accounts/-1")
950
951 assert %{"error" => "Can't find user"} = json_response(conn, 404)
952 end
953
954 test "media upload", %{conn: conn} do
955 file = %Plug.Upload{
956 content_type: "image/jpg",
957 path: Path.absname("test/fixtures/image.jpg"),
958 filename: "an_image.jpg"
959 }
960
961 desc = "Description of the image"
962
963 user = insert(:user)
964
965 conn =
966 conn
967 |> assign(:user, user)
968 |> post("/api/v1/media", %{"file" => file, "description" => desc})
969
970 assert media = json_response(conn, 200)
971
972 assert media["type"] == "image"
973 assert media["description"] == desc
974 assert media["id"]
975
976 object = Repo.get(Object, media["id"])
977 assert object.data["actor"] == User.ap_id(user)
978 end
979
980 test "hashtag timeline", %{conn: conn} do
981 following = insert(:user)
982
983 capture_log(fn ->
984 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
985
986 {:ok, [_activity]} =
987 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
988
989 nconn =
990 conn
991 |> get("/api/v1/timelines/tag/2hu")
992
993 assert [%{"id" => id}] = json_response(nconn, 200)
994
995 assert id == to_string(activity.id)
996
997 # works for different capitalization too
998 nconn =
999 conn
1000 |> get("/api/v1/timelines/tag/2HU")
1001
1002 assert [%{"id" => id}] = json_response(nconn, 200)
1003
1004 assert id == to_string(activity.id)
1005 end)
1006 end
1007
1008 test "getting followers", %{conn: conn} do
1009 user = insert(:user)
1010 other_user = insert(:user)
1011 {:ok, user} = User.follow(user, other_user)
1012
1013 conn =
1014 conn
1015 |> get("/api/v1/accounts/#{other_user.id}/followers")
1016
1017 assert [%{"id" => id}] = json_response(conn, 200)
1018 assert id == to_string(user.id)
1019 end
1020
1021 test "getting followers, hide_network", %{conn: conn} do
1022 user = insert(:user)
1023 other_user = insert(:user, %{info: %{hide_network: true}})
1024 {:ok, _user} = User.follow(user, other_user)
1025
1026 conn =
1027 conn
1028 |> get("/api/v1/accounts/#{other_user.id}/followers")
1029
1030 assert [] == json_response(conn, 200)
1031 end
1032
1033 test "getting followers, hide_network, same user requesting", %{conn: conn} do
1034 user = insert(:user)
1035 other_user = insert(:user, %{info: %{hide_network: true}})
1036 {:ok, _user} = User.follow(user, other_user)
1037
1038 conn =
1039 conn
1040 |> assign(:user, other_user)
1041 |> get("/api/v1/accounts/#{other_user.id}/followers")
1042
1043 refute [] == json_response(conn, 200)
1044 end
1045
1046 test "getting following", %{conn: conn} do
1047 user = insert(:user)
1048 other_user = insert(:user)
1049 {:ok, user} = User.follow(user, other_user)
1050
1051 conn =
1052 conn
1053 |> get("/api/v1/accounts/#{user.id}/following")
1054
1055 assert [%{"id" => id}] = json_response(conn, 200)
1056 assert id == to_string(other_user.id)
1057 end
1058
1059 test "getting following, hide_network", %{conn: conn} do
1060 user = insert(:user, %{info: %{hide_network: true}})
1061 other_user = insert(:user)
1062 {:ok, user} = User.follow(user, other_user)
1063
1064 conn =
1065 conn
1066 |> get("/api/v1/accounts/#{user.id}/following")
1067
1068 assert [] == json_response(conn, 200)
1069 end
1070
1071 test "getting following, hide_network, same user requesting", %{conn: conn} do
1072 user = insert(:user, %{info: %{hide_network: true}})
1073 other_user = insert(:user)
1074 {:ok, user} = User.follow(user, other_user)
1075
1076 conn =
1077 conn
1078 |> assign(:user, user)
1079 |> get("/api/v1/accounts/#{user.id}/following")
1080
1081 refute [] == json_response(conn, 200)
1082 end
1083
1084 test "following / unfollowing a user", %{conn: conn} do
1085 user = insert(:user)
1086 other_user = insert(:user)
1087
1088 conn =
1089 conn
1090 |> assign(:user, user)
1091 |> post("/api/v1/accounts/#{other_user.id}/follow")
1092
1093 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1094
1095 user = Repo.get(User, user.id)
1096
1097 conn =
1098 build_conn()
1099 |> assign(:user, user)
1100 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1101
1102 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1103
1104 user = Repo.get(User, user.id)
1105
1106 conn =
1107 build_conn()
1108 |> assign(:user, user)
1109 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1110
1111 assert %{"id" => id} = json_response(conn, 200)
1112 assert id == to_string(other_user.id)
1113 end
1114
1115 test "blocking / unblocking a user", %{conn: conn} do
1116 user = insert(:user)
1117 other_user = insert(:user)
1118
1119 conn =
1120 conn
1121 |> assign(:user, user)
1122 |> post("/api/v1/accounts/#{other_user.id}/block")
1123
1124 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1125
1126 user = Repo.get(User, user.id)
1127
1128 conn =
1129 build_conn()
1130 |> assign(:user, user)
1131 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1132
1133 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1134 end
1135
1136 test "getting a list of blocks", %{conn: conn} do
1137 user = insert(:user)
1138 other_user = insert(:user)
1139
1140 {:ok, user} = User.block(user, other_user)
1141
1142 conn =
1143 conn
1144 |> assign(:user, user)
1145 |> get("/api/v1/blocks")
1146
1147 other_user_id = to_string(other_user.id)
1148 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1149 end
1150
1151 test "blocking / unblocking a domain", %{conn: conn} do
1152 user = insert(:user)
1153 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1154
1155 conn =
1156 conn
1157 |> assign(:user, user)
1158 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1159
1160 assert %{} = json_response(conn, 200)
1161 user = User.get_cached_by_ap_id(user.ap_id)
1162 assert User.blocks?(user, other_user)
1163
1164 conn =
1165 build_conn()
1166 |> assign(:user, user)
1167 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1168
1169 assert %{} = json_response(conn, 200)
1170 user = User.get_cached_by_ap_id(user.ap_id)
1171 refute User.blocks?(user, other_user)
1172 end
1173
1174 test "getting a list of domain blocks", %{conn: conn} do
1175 user = insert(:user)
1176
1177 {:ok, user} = User.block_domain(user, "bad.site")
1178 {:ok, user} = User.block_domain(user, "even.worse.site")
1179
1180 conn =
1181 conn
1182 |> assign(:user, user)
1183 |> get("/api/v1/domain_blocks")
1184
1185 domain_blocks = json_response(conn, 200)
1186
1187 assert "bad.site" in domain_blocks
1188 assert "even.worse.site" in domain_blocks
1189 end
1190
1191 test "unimplemented mute endpoints" do
1192 user = insert(:user)
1193 other_user = insert(:user)
1194
1195 ["mute", "unmute"]
1196 |> Enum.each(fn endpoint ->
1197 conn =
1198 build_conn()
1199 |> assign(:user, user)
1200 |> post("/api/v1/accounts/#{other_user.id}/#{endpoint}")
1201
1202 assert %{"id" => id} = json_response(conn, 200)
1203 assert id == to_string(other_user.id)
1204 end)
1205 end
1206
1207 test "unimplemented mutes, follow_requests, blocks, domain blocks" do
1208 user = insert(:user)
1209
1210 ["blocks", "domain_blocks", "mutes", "follow_requests"]
1211 |> Enum.each(fn endpoint ->
1212 conn =
1213 build_conn()
1214 |> assign(:user, user)
1215 |> get("/api/v1/#{endpoint}")
1216
1217 assert [] = json_response(conn, 200)
1218 end)
1219 end
1220
1221 test "account search", %{conn: conn} do
1222 user = insert(:user)
1223 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1224 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1225
1226 results =
1227 conn
1228 |> assign(:user, user)
1229 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1230 |> json_response(200)
1231
1232 result_ids = for result <- results, do: result["acct"]
1233
1234 assert user_two.nickname in result_ids
1235 assert user_three.nickname in result_ids
1236
1237 results =
1238 conn
1239 |> assign(:user, user)
1240 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1241 |> json_response(200)
1242
1243 result_ids = for result <- results, do: result["acct"]
1244
1245 assert user_three.nickname in result_ids
1246 end
1247
1248 test "search", %{conn: conn} do
1249 user = insert(:user)
1250 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1251 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1252
1253 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1254
1255 {:ok, _activity} =
1256 CommonAPI.post(user, %{
1257 "status" => "This is about 2hu, but private",
1258 "visibility" => "private"
1259 })
1260
1261 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1262
1263 conn =
1264 conn
1265 |> get("/api/v1/search", %{"q" => "2hu"})
1266
1267 assert results = json_response(conn, 200)
1268
1269 [account | _] = results["accounts"]
1270 assert account["id"] == to_string(user_three.id)
1271
1272 assert results["hashtags"] == []
1273
1274 [status] = results["statuses"]
1275 assert status["id"] == to_string(activity.id)
1276 end
1277
1278 test "search fetches remote statuses", %{conn: conn} do
1279 capture_log(fn ->
1280 conn =
1281 conn
1282 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1283
1284 assert results = json_response(conn, 200)
1285
1286 [status] = results["statuses"]
1287 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1288 end)
1289 end
1290
1291 test "search fetches remote accounts", %{conn: conn} do
1292 conn =
1293 conn
1294 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1295
1296 assert results = json_response(conn, 200)
1297 [account] = results["accounts"]
1298 assert account["acct"] == "shp@social.heldscal.la"
1299 end
1300
1301 test "returns the favorites of a user", %{conn: conn} do
1302 user = insert(:user)
1303 other_user = insert(:user)
1304
1305 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1306 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1307
1308 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1309
1310 conn =
1311 conn
1312 |> assign(:user, user)
1313 |> get("/api/v1/favourites")
1314
1315 assert [status] = json_response(conn, 200)
1316 assert status["id"] == to_string(activity.id)
1317 end
1318
1319 describe "updating credentials" do
1320 test "updates the user's bio", %{conn: conn} do
1321 user = insert(:user)
1322 user2 = insert(:user)
1323
1324 conn =
1325 conn
1326 |> assign(:user, user)
1327 |> patch("/api/v1/accounts/update_credentials", %{
1328 "note" => "I drink #cofe with @#{user2.nickname}"
1329 })
1330
1331 assert user = json_response(conn, 200)
1332
1333 assert user["note"] ==
1334 "I drink <a data-tag=\"cofe\" href=\"http://localhost:4001/tag/cofe\">#cofe</a> with <span><a data-user=\"#{
1335 user2.id
1336 }\" href=\"#{user2.ap_id}\">@<span>#{user2.nickname}</span></a></span>"
1337 end
1338
1339 test "updates the user's locking status", %{conn: conn} do
1340 user = insert(:user)
1341
1342 conn =
1343 conn
1344 |> assign(:user, user)
1345 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
1346
1347 assert user = json_response(conn, 200)
1348 assert user["locked"] == true
1349 end
1350
1351 test "updates the user's name", %{conn: conn} do
1352 user = insert(:user)
1353
1354 conn =
1355 conn
1356 |> assign(:user, user)
1357 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
1358
1359 assert user = json_response(conn, 200)
1360 assert user["display_name"] == "markorepairs"
1361 end
1362
1363 test "updates the user's avatar", %{conn: conn} do
1364 user = insert(:user)
1365
1366 new_avatar = %Plug.Upload{
1367 content_type: "image/jpg",
1368 path: Path.absname("test/fixtures/image.jpg"),
1369 filename: "an_image.jpg"
1370 }
1371
1372 conn =
1373 conn
1374 |> assign(:user, user)
1375 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
1376
1377 assert user_response = json_response(conn, 200)
1378 assert user_response["avatar"] != User.avatar_url(user)
1379 end
1380
1381 test "updates the user's banner", %{conn: conn} do
1382 user = insert(:user)
1383
1384 new_header = %Plug.Upload{
1385 content_type: "image/jpg",
1386 path: Path.absname("test/fixtures/image.jpg"),
1387 filename: "an_image.jpg"
1388 }
1389
1390 conn =
1391 conn
1392 |> assign(:user, user)
1393 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
1394
1395 assert user_response = json_response(conn, 200)
1396 assert user_response["header"] != User.banner_url(user)
1397 end
1398 end
1399
1400 test "get instance information", %{conn: conn} do
1401 insert(:user, %{local: true})
1402 user = insert(:user, %{local: true})
1403 insert(:user, %{local: false})
1404
1405 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
1406
1407 Pleroma.Stats.update_stats()
1408
1409 conn =
1410 conn
1411 |> get("/api/v1/instance")
1412
1413 assert result = json_response(conn, 200)
1414
1415 assert result["stats"]["user_count"] == 2
1416 assert result["stats"]["status_count"] == 1
1417 end
1418
1419 test "put settings", %{conn: conn} do
1420 user = insert(:user)
1421
1422 conn =
1423 conn
1424 |> assign(:user, user)
1425 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
1426
1427 assert result = json_response(conn, 200)
1428
1429 user = User.get_cached_by_ap_id(user.ap_id)
1430 assert user.info.settings == %{"programming" => "socks"}
1431 end
1432 end