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