Merge branch 'develop' into feature/788-separate-email-addresses
[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.data["object"]["inReplyToStatusId"] == 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 end
948
949 describe "reblogging" do
950 test "reblogs and returns the reblogged status", %{conn: conn} do
951 activity = insert(:note_activity)
952 user = insert(:user)
953
954 conn =
955 conn
956 |> assign(:user, user)
957 |> post("/api/v1/statuses/#{activity.id}/reblog")
958
959 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
960 json_response(conn, 200)
961
962 assert to_string(activity.id) == id
963 end
964 end
965
966 describe "unreblogging" do
967 test "unreblogs and returns the unreblogged status", %{conn: conn} do
968 activity = insert(:note_activity)
969 user = insert(:user)
970
971 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
972
973 conn =
974 conn
975 |> assign(:user, user)
976 |> post("/api/v1/statuses/#{activity.id}/unreblog")
977
978 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
979
980 assert to_string(activity.id) == id
981 end
982 end
983
984 describe "favoriting" do
985 test "favs a status and returns it", %{conn: conn} do
986 activity = insert(:note_activity)
987 user = insert(:user)
988
989 conn =
990 conn
991 |> assign(:user, user)
992 |> post("/api/v1/statuses/#{activity.id}/favourite")
993
994 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
995 json_response(conn, 200)
996
997 assert to_string(activity.id) == id
998 end
999
1000 test "returns 500 for a wrong id", %{conn: conn} do
1001 user = insert(:user)
1002
1003 resp =
1004 conn
1005 |> assign(:user, user)
1006 |> post("/api/v1/statuses/1/favourite")
1007 |> json_response(500)
1008
1009 assert resp == "Something went wrong"
1010 end
1011 end
1012
1013 describe "unfavoriting" do
1014 test "unfavorites a status and returns it", %{conn: conn} do
1015 activity = insert(:note_activity)
1016 user = insert(:user)
1017
1018 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1019
1020 conn =
1021 conn
1022 |> assign(:user, user)
1023 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1024
1025 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1026 json_response(conn, 200)
1027
1028 assert to_string(activity.id) == id
1029 end
1030 end
1031
1032 describe "user timelines" do
1033 test "gets a users statuses", %{conn: conn} do
1034 user_one = insert(:user)
1035 user_two = insert(:user)
1036 user_three = insert(:user)
1037
1038 {:ok, user_three} = User.follow(user_three, user_one)
1039
1040 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1041
1042 {:ok, direct_activity} =
1043 CommonAPI.post(user_one, %{
1044 "status" => "Hi, @#{user_two.nickname}.",
1045 "visibility" => "direct"
1046 })
1047
1048 {:ok, private_activity} =
1049 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1050
1051 resp =
1052 conn
1053 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1054
1055 assert [%{"id" => id}] = json_response(resp, 200)
1056 assert id == to_string(activity.id)
1057
1058 resp =
1059 conn
1060 |> assign(:user, user_two)
1061 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1062
1063 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1064 assert id_one == to_string(direct_activity.id)
1065 assert id_two == to_string(activity.id)
1066
1067 resp =
1068 conn
1069 |> assign(:user, user_three)
1070 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1071
1072 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1073 assert id_one == to_string(private_activity.id)
1074 assert id_two == to_string(activity.id)
1075 end
1076
1077 test "unimplemented pinned statuses feature", %{conn: conn} do
1078 note = insert(:note_activity)
1079 user = User.get_by_ap_id(note.data["actor"])
1080
1081 conn =
1082 conn
1083 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1084
1085 assert json_response(conn, 200) == []
1086 end
1087
1088 test "gets an users media", %{conn: conn} do
1089 note = insert(:note_activity)
1090 user = User.get_by_ap_id(note.data["actor"])
1091
1092 file = %Plug.Upload{
1093 content_type: "image/jpg",
1094 path: Path.absname("test/fixtures/image.jpg"),
1095 filename: "an_image.jpg"
1096 }
1097
1098 media =
1099 TwitterAPI.upload(file, user, "json")
1100 |> Poison.decode!()
1101
1102 {:ok, image_post} =
1103 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1104
1105 conn =
1106 conn
1107 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1108
1109 assert [%{"id" => id}] = json_response(conn, 200)
1110 assert id == to_string(image_post.id)
1111
1112 conn =
1113 build_conn()
1114 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1115
1116 assert [%{"id" => id}] = json_response(conn, 200)
1117 assert id == to_string(image_post.id)
1118 end
1119
1120 test "gets a user's statuses without reblogs", %{conn: conn} do
1121 user = insert(:user)
1122 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1123 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1124
1125 conn =
1126 conn
1127 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1128
1129 assert [%{"id" => id}] = json_response(conn, 200)
1130 assert id == to_string(post.id)
1131
1132 conn =
1133 conn
1134 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1135
1136 assert [%{"id" => id}] = json_response(conn, 200)
1137 assert id == to_string(post.id)
1138 end
1139 end
1140
1141 describe "user relationships" do
1142 test "returns the relationships for the current user", %{conn: conn} do
1143 user = insert(:user)
1144 other_user = insert(:user)
1145 {:ok, user} = User.follow(user, other_user)
1146
1147 conn =
1148 conn
1149 |> assign(:user, user)
1150 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1151
1152 assert [relationship] = json_response(conn, 200)
1153
1154 assert to_string(other_user.id) == relationship["id"]
1155 end
1156 end
1157
1158 describe "locked accounts" do
1159 test "/api/v1/follow_requests works" do
1160 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1161 other_user = insert(:user)
1162
1163 {:ok, _activity} = ActivityPub.follow(other_user, user)
1164
1165 user = User.get_by_id(user.id)
1166 other_user = User.get_by_id(other_user.id)
1167
1168 assert User.following?(other_user, user) == false
1169
1170 conn =
1171 build_conn()
1172 |> assign(:user, user)
1173 |> get("/api/v1/follow_requests")
1174
1175 assert [relationship] = json_response(conn, 200)
1176 assert to_string(other_user.id) == relationship["id"]
1177 end
1178
1179 test "/api/v1/follow_requests/:id/authorize works" do
1180 user = insert(:user, %{info: %User.Info{locked: true}})
1181 other_user = insert(:user)
1182
1183 {:ok, _activity} = ActivityPub.follow(other_user, user)
1184
1185 user = User.get_by_id(user.id)
1186 other_user = User.get_by_id(other_user.id)
1187
1188 assert User.following?(other_user, user) == false
1189
1190 conn =
1191 build_conn()
1192 |> assign(:user, user)
1193 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1194
1195 assert relationship = json_response(conn, 200)
1196 assert to_string(other_user.id) == relationship["id"]
1197
1198 user = User.get_by_id(user.id)
1199 other_user = User.get_by_id(other_user.id)
1200
1201 assert User.following?(other_user, user) == true
1202 end
1203
1204 test "verify_credentials", %{conn: conn} do
1205 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1206
1207 conn =
1208 conn
1209 |> assign(:user, user)
1210 |> get("/api/v1/accounts/verify_credentials")
1211
1212 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1213 assert id == to_string(user.id)
1214 end
1215
1216 test "/api/v1/follow_requests/:id/reject works" do
1217 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1218 other_user = insert(:user)
1219
1220 {:ok, _activity} = ActivityPub.follow(other_user, user)
1221
1222 user = User.get_by_id(user.id)
1223
1224 conn =
1225 build_conn()
1226 |> assign(:user, user)
1227 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1228
1229 assert relationship = json_response(conn, 200)
1230 assert to_string(other_user.id) == relationship["id"]
1231
1232 user = User.get_by_id(user.id)
1233 other_user = User.get_by_id(other_user.id)
1234
1235 assert User.following?(other_user, user) == false
1236 end
1237 end
1238
1239 test "account fetching", %{conn: conn} do
1240 user = insert(:user)
1241
1242 conn =
1243 conn
1244 |> get("/api/v1/accounts/#{user.id}")
1245
1246 assert %{"id" => id} = json_response(conn, 200)
1247 assert id == to_string(user.id)
1248
1249 conn =
1250 build_conn()
1251 |> get("/api/v1/accounts/-1")
1252
1253 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1254 end
1255
1256 test "account fetching also works nickname", %{conn: conn} do
1257 user = insert(:user)
1258
1259 conn =
1260 conn
1261 |> get("/api/v1/accounts/#{user.nickname}")
1262
1263 assert %{"id" => id} = json_response(conn, 200)
1264 assert id == user.id
1265 end
1266
1267 test "media upload", %{conn: conn} do
1268 file = %Plug.Upload{
1269 content_type: "image/jpg",
1270 path: Path.absname("test/fixtures/image.jpg"),
1271 filename: "an_image.jpg"
1272 }
1273
1274 desc = "Description of the image"
1275
1276 user = insert(:user)
1277
1278 conn =
1279 conn
1280 |> assign(:user, user)
1281 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1282
1283 assert media = json_response(conn, 200)
1284
1285 assert media["type"] == "image"
1286 assert media["description"] == desc
1287 assert media["id"]
1288
1289 object = Repo.get(Object, media["id"])
1290 assert object.data["actor"] == User.ap_id(user)
1291 end
1292
1293 test "hashtag timeline", %{conn: conn} do
1294 following = insert(:user)
1295
1296 capture_log(fn ->
1297 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1298
1299 {:ok, [_activity]} =
1300 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1301
1302 nconn =
1303 conn
1304 |> get("/api/v1/timelines/tag/2hu")
1305
1306 assert [%{"id" => id}] = json_response(nconn, 200)
1307
1308 assert id == to_string(activity.id)
1309
1310 # works for different capitalization too
1311 nconn =
1312 conn
1313 |> get("/api/v1/timelines/tag/2HU")
1314
1315 assert [%{"id" => id}] = json_response(nconn, 200)
1316
1317 assert id == to_string(activity.id)
1318 end)
1319 end
1320
1321 test "multi-hashtag timeline", %{conn: conn} do
1322 user = insert(:user)
1323
1324 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1325 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1326 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1327
1328 any_test =
1329 conn
1330 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1331
1332 [status_none, status_test1, status_test] = json_response(any_test, 200)
1333
1334 assert to_string(activity_test.id) == status_test["id"]
1335 assert to_string(activity_test1.id) == status_test1["id"]
1336 assert to_string(activity_none.id) == status_none["id"]
1337
1338 restricted_test =
1339 conn
1340 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1341
1342 assert [status_test1] == json_response(restricted_test, 200)
1343
1344 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1345
1346 assert [status_none] == json_response(all_test, 200)
1347 end
1348
1349 test "getting followers", %{conn: conn} do
1350 user = insert(:user)
1351 other_user = insert(:user)
1352 {:ok, user} = User.follow(user, other_user)
1353
1354 conn =
1355 conn
1356 |> get("/api/v1/accounts/#{other_user.id}/followers")
1357
1358 assert [%{"id" => id}] = json_response(conn, 200)
1359 assert id == to_string(user.id)
1360 end
1361
1362 test "getting followers, hide_followers", %{conn: conn} do
1363 user = insert(:user)
1364 other_user = insert(:user, %{info: %{hide_followers: true}})
1365 {:ok, _user} = User.follow(user, other_user)
1366
1367 conn =
1368 conn
1369 |> get("/api/v1/accounts/#{other_user.id}/followers")
1370
1371 assert [] == json_response(conn, 200)
1372 end
1373
1374 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1375 user = insert(:user)
1376 other_user = insert(:user, %{info: %{hide_followers: true}})
1377 {:ok, _user} = User.follow(user, other_user)
1378
1379 conn =
1380 conn
1381 |> assign(:user, other_user)
1382 |> get("/api/v1/accounts/#{other_user.id}/followers")
1383
1384 refute [] == json_response(conn, 200)
1385 end
1386
1387 test "getting followers, pagination", %{conn: conn} do
1388 user = insert(:user)
1389 follower1 = insert(:user)
1390 follower2 = insert(:user)
1391 follower3 = insert(:user)
1392 {:ok, _} = User.follow(follower1, user)
1393 {:ok, _} = User.follow(follower2, user)
1394 {:ok, _} = User.follow(follower3, user)
1395
1396 conn =
1397 conn
1398 |> assign(:user, user)
1399
1400 res_conn =
1401 conn
1402 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1403
1404 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1405 assert id3 == follower3.id
1406 assert id2 == follower2.id
1407
1408 res_conn =
1409 conn
1410 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1411
1412 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1413 assert id2 == follower2.id
1414 assert id1 == follower1.id
1415
1416 res_conn =
1417 conn
1418 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1419
1420 assert [%{"id" => id2}] = json_response(res_conn, 200)
1421 assert id2 == follower2.id
1422
1423 assert [link_header] = get_resp_header(res_conn, "link")
1424 assert link_header =~ ~r/since_id=#{follower2.id}/
1425 assert link_header =~ ~r/max_id=#{follower2.id}/
1426 end
1427
1428 test "getting following", %{conn: conn} do
1429 user = insert(:user)
1430 other_user = insert(:user)
1431 {:ok, user} = User.follow(user, other_user)
1432
1433 conn =
1434 conn
1435 |> get("/api/v1/accounts/#{user.id}/following")
1436
1437 assert [%{"id" => id}] = json_response(conn, 200)
1438 assert id == to_string(other_user.id)
1439 end
1440
1441 test "getting following, hide_follows", %{conn: conn} do
1442 user = insert(:user, %{info: %{hide_follows: true}})
1443 other_user = insert(:user)
1444 {:ok, user} = User.follow(user, other_user)
1445
1446 conn =
1447 conn
1448 |> get("/api/v1/accounts/#{user.id}/following")
1449
1450 assert [] == json_response(conn, 200)
1451 end
1452
1453 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1454 user = insert(:user, %{info: %{hide_follows: true}})
1455 other_user = insert(:user)
1456 {:ok, user} = User.follow(user, other_user)
1457
1458 conn =
1459 conn
1460 |> assign(:user, user)
1461 |> get("/api/v1/accounts/#{user.id}/following")
1462
1463 refute [] == json_response(conn, 200)
1464 end
1465
1466 test "getting following, pagination", %{conn: conn} do
1467 user = insert(:user)
1468 following1 = insert(:user)
1469 following2 = insert(:user)
1470 following3 = insert(:user)
1471 {:ok, _} = User.follow(user, following1)
1472 {:ok, _} = User.follow(user, following2)
1473 {:ok, _} = User.follow(user, following3)
1474
1475 conn =
1476 conn
1477 |> assign(:user, user)
1478
1479 res_conn =
1480 conn
1481 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1482
1483 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1484 assert id3 == following3.id
1485 assert id2 == following2.id
1486
1487 res_conn =
1488 conn
1489 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1490
1491 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1492 assert id2 == following2.id
1493 assert id1 == following1.id
1494
1495 res_conn =
1496 conn
1497 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1498
1499 assert [%{"id" => id2}] = json_response(res_conn, 200)
1500 assert id2 == following2.id
1501
1502 assert [link_header] = get_resp_header(res_conn, "link")
1503 assert link_header =~ ~r/since_id=#{following2.id}/
1504 assert link_header =~ ~r/max_id=#{following2.id}/
1505 end
1506
1507 test "following / unfollowing a user", %{conn: conn} do
1508 user = insert(:user)
1509 other_user = insert(:user)
1510
1511 conn =
1512 conn
1513 |> assign(:user, user)
1514 |> post("/api/v1/accounts/#{other_user.id}/follow")
1515
1516 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1517
1518 user = User.get_by_id(user.id)
1519
1520 conn =
1521 build_conn()
1522 |> assign(:user, user)
1523 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1524
1525 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1526
1527 user = User.get_by_id(user.id)
1528
1529 conn =
1530 build_conn()
1531 |> assign(:user, user)
1532 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1533
1534 assert %{"id" => id} = json_response(conn, 200)
1535 assert id == to_string(other_user.id)
1536 end
1537
1538 test "muting / unmuting a user", %{conn: conn} do
1539 user = insert(:user)
1540 other_user = insert(:user)
1541
1542 conn =
1543 conn
1544 |> assign(:user, user)
1545 |> post("/api/v1/accounts/#{other_user.id}/mute")
1546
1547 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1548
1549 user = User.get_by_id(user.id)
1550
1551 conn =
1552 build_conn()
1553 |> assign(:user, user)
1554 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1555
1556 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1557 end
1558
1559 test "subscribing / unsubscribing to a user", %{conn: conn} do
1560 user = insert(:user)
1561 subscription_target = insert(:user)
1562
1563 conn =
1564 conn
1565 |> assign(:user, user)
1566 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1567
1568 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1569
1570 conn =
1571 build_conn()
1572 |> assign(:user, user)
1573 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1574
1575 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1576 end
1577
1578 test "getting a list of mutes", %{conn: conn} do
1579 user = insert(:user)
1580 other_user = insert(:user)
1581
1582 {:ok, user} = User.mute(user, other_user)
1583
1584 conn =
1585 conn
1586 |> assign(:user, user)
1587 |> get("/api/v1/mutes")
1588
1589 other_user_id = to_string(other_user.id)
1590 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1591 end
1592
1593 test "blocking / unblocking a user", %{conn: conn} do
1594 user = insert(:user)
1595 other_user = insert(:user)
1596
1597 conn =
1598 conn
1599 |> assign(:user, user)
1600 |> post("/api/v1/accounts/#{other_user.id}/block")
1601
1602 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1603
1604 user = User.get_by_id(user.id)
1605
1606 conn =
1607 build_conn()
1608 |> assign(:user, user)
1609 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1610
1611 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1612 end
1613
1614 test "getting a list of blocks", %{conn: conn} do
1615 user = insert(:user)
1616 other_user = insert(:user)
1617
1618 {:ok, user} = User.block(user, other_user)
1619
1620 conn =
1621 conn
1622 |> assign(:user, user)
1623 |> get("/api/v1/blocks")
1624
1625 other_user_id = to_string(other_user.id)
1626 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1627 end
1628
1629 test "blocking / unblocking a domain", %{conn: conn} do
1630 user = insert(:user)
1631 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1632
1633 conn =
1634 conn
1635 |> assign(:user, user)
1636 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1637
1638 assert %{} = json_response(conn, 200)
1639 user = User.get_cached_by_ap_id(user.ap_id)
1640 assert User.blocks?(user, other_user)
1641
1642 conn =
1643 build_conn()
1644 |> assign(:user, user)
1645 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1646
1647 assert %{} = json_response(conn, 200)
1648 user = User.get_cached_by_ap_id(user.ap_id)
1649 refute User.blocks?(user, other_user)
1650 end
1651
1652 test "getting a list of domain blocks", %{conn: conn} do
1653 user = insert(:user)
1654
1655 {:ok, user} = User.block_domain(user, "bad.site")
1656 {:ok, user} = User.block_domain(user, "even.worse.site")
1657
1658 conn =
1659 conn
1660 |> assign(:user, user)
1661 |> get("/api/v1/domain_blocks")
1662
1663 domain_blocks = json_response(conn, 200)
1664
1665 assert "bad.site" in domain_blocks
1666 assert "even.worse.site" in domain_blocks
1667 end
1668
1669 test "unimplemented follow_requests, blocks, domain blocks" do
1670 user = insert(:user)
1671
1672 ["blocks", "domain_blocks", "follow_requests"]
1673 |> Enum.each(fn endpoint ->
1674 conn =
1675 build_conn()
1676 |> assign(:user, user)
1677 |> get("/api/v1/#{endpoint}")
1678
1679 assert [] = json_response(conn, 200)
1680 end)
1681 end
1682
1683 test "account search", %{conn: conn} do
1684 user = insert(:user)
1685 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1686 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1687
1688 results =
1689 conn
1690 |> assign(:user, user)
1691 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1692 |> json_response(200)
1693
1694 result_ids = for result <- results, do: result["acct"]
1695
1696 assert user_two.nickname in result_ids
1697 assert user_three.nickname in result_ids
1698
1699 results =
1700 conn
1701 |> assign(:user, user)
1702 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1703 |> json_response(200)
1704
1705 result_ids = for result <- results, do: result["acct"]
1706
1707 assert user_three.nickname in result_ids
1708 end
1709
1710 test "search", %{conn: conn} do
1711 user = insert(:user)
1712 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1713 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1714
1715 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1716
1717 {:ok, _activity} =
1718 CommonAPI.post(user, %{
1719 "status" => "This is about 2hu, but private",
1720 "visibility" => "private"
1721 })
1722
1723 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1724
1725 conn =
1726 conn
1727 |> get("/api/v1/search", %{"q" => "2hu"})
1728
1729 assert results = json_response(conn, 200)
1730
1731 [account | _] = results["accounts"]
1732 assert account["id"] == to_string(user_three.id)
1733
1734 assert results["hashtags"] == []
1735
1736 [status] = results["statuses"]
1737 assert status["id"] == to_string(activity.id)
1738 end
1739
1740 test "search fetches remote statuses", %{conn: conn} do
1741 capture_log(fn ->
1742 conn =
1743 conn
1744 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1745
1746 assert results = json_response(conn, 200)
1747
1748 [status] = results["statuses"]
1749 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1750 end)
1751 end
1752
1753 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1754 {:ok, activity} =
1755 CommonAPI.post(insert(:user), %{
1756 "status" => "This is about 2hu, but private",
1757 "visibility" => "private"
1758 })
1759
1760 capture_log(fn ->
1761 conn =
1762 conn
1763 |> get("/api/v1/search", %{"q" => activity.data["object"]["id"]})
1764
1765 assert results = json_response(conn, 200)
1766
1767 [] = results["statuses"]
1768 end)
1769 end
1770
1771 test "search fetches remote accounts", %{conn: conn} do
1772 conn =
1773 conn
1774 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1775
1776 assert results = json_response(conn, 200)
1777 [account] = results["accounts"]
1778 assert account["acct"] == "shp@social.heldscal.la"
1779 end
1780
1781 test "returns the favorites of a user", %{conn: conn} do
1782 user = insert(:user)
1783 other_user = insert(:user)
1784
1785 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
1786 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
1787
1788 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1789
1790 first_conn =
1791 conn
1792 |> assign(:user, user)
1793 |> get("/api/v1/favourites")
1794
1795 assert [status] = json_response(first_conn, 200)
1796 assert status["id"] == to_string(activity.id)
1797
1798 assert [{"link", _link_header}] =
1799 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
1800
1801 # Honours query params
1802 {:ok, second_activity} =
1803 CommonAPI.post(other_user, %{
1804 "status" =>
1805 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
1806 })
1807
1808 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
1809
1810 last_like = status["id"]
1811
1812 second_conn =
1813 conn
1814 |> assign(:user, user)
1815 |> get("/api/v1/favourites?since_id=#{last_like}")
1816
1817 assert [second_status] = json_response(second_conn, 200)
1818 assert second_status["id"] == to_string(second_activity.id)
1819
1820 third_conn =
1821 conn
1822 |> assign(:user, user)
1823 |> get("/api/v1/favourites?limit=0")
1824
1825 assert [] = json_response(third_conn, 200)
1826 end
1827
1828 describe "updating credentials" do
1829 test "updates the user's bio", %{conn: conn} do
1830 user = insert(:user)
1831 user2 = insert(:user)
1832
1833 conn =
1834 conn
1835 |> assign(:user, user)
1836 |> patch("/api/v1/accounts/update_credentials", %{
1837 "note" => "I drink #cofe with @#{user2.nickname}"
1838 })
1839
1840 assert user = json_response(conn, 200)
1841
1842 assert user["note"] ==
1843 ~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=") <>
1844 user2.id <>
1845 ~s(" class="u-url mention" href=") <>
1846 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
1847 end
1848
1849 test "updates the user's locking status", %{conn: conn} do
1850 user = insert(:user)
1851
1852 conn =
1853 conn
1854 |> assign(:user, user)
1855 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
1856
1857 assert user = json_response(conn, 200)
1858 assert user["locked"] == true
1859 end
1860
1861 test "updates the user's name", %{conn: conn} do
1862 user = insert(:user)
1863
1864 conn =
1865 conn
1866 |> assign(:user, user)
1867 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
1868
1869 assert user = json_response(conn, 200)
1870 assert user["display_name"] == "markorepairs"
1871 end
1872
1873 test "updates the user's avatar", %{conn: conn} do
1874 user = insert(:user)
1875
1876 new_avatar = %Plug.Upload{
1877 content_type: "image/jpg",
1878 path: Path.absname("test/fixtures/image.jpg"),
1879 filename: "an_image.jpg"
1880 }
1881
1882 conn =
1883 conn
1884 |> assign(:user, user)
1885 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
1886
1887 assert user_response = json_response(conn, 200)
1888 assert user_response["avatar"] != User.avatar_url(user)
1889 end
1890
1891 test "updates the user's banner", %{conn: conn} do
1892 user = insert(:user)
1893
1894 new_header = %Plug.Upload{
1895 content_type: "image/jpg",
1896 path: Path.absname("test/fixtures/image.jpg"),
1897 filename: "an_image.jpg"
1898 }
1899
1900 conn =
1901 conn
1902 |> assign(:user, user)
1903 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
1904
1905 assert user_response = json_response(conn, 200)
1906 assert user_response["header"] != User.banner_url(user)
1907 end
1908
1909 test "requires 'write' permission", %{conn: conn} do
1910 token1 = insert(:oauth_token, scopes: ["read"])
1911 token2 = insert(:oauth_token, scopes: ["write", "follow"])
1912
1913 for token <- [token1, token2] do
1914 conn =
1915 conn
1916 |> put_req_header("authorization", "Bearer #{token.token}")
1917 |> patch("/api/v1/accounts/update_credentials", %{})
1918
1919 if token == token1 do
1920 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
1921 else
1922 assert json_response(conn, 200)
1923 end
1924 end
1925 end
1926 end
1927
1928 test "get instance information", %{conn: conn} do
1929 conn = get(conn, "/api/v1/instance")
1930 assert result = json_response(conn, 200)
1931
1932 email = Pleroma.Config.get([:instance, :email])
1933 # Note: not checking for "max_toot_chars" since it's optional
1934 assert %{
1935 "uri" => _,
1936 "title" => _,
1937 "description" => _,
1938 "version" => _,
1939 "email" => from_config_email,
1940 "urls" => %{
1941 "streaming_api" => _
1942 },
1943 "stats" => _,
1944 "thumbnail" => _,
1945 "languages" => _,
1946 "registrations" => _
1947 } = result
1948
1949 assert email == from_config_email
1950 end
1951
1952 test "get instance stats", %{conn: conn} do
1953 user = insert(:user, %{local: true})
1954
1955 user2 = insert(:user, %{local: true})
1956 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
1957
1958 insert(:user, %{local: false, nickname: "u@peer1.com"})
1959 insert(:user, %{local: false, nickname: "u@peer2.com"})
1960
1961 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
1962
1963 # Stats should count users with missing or nil `info.deactivated` value
1964 user = User.get_by_id(user.id)
1965 info_change = Changeset.change(user.info, %{deactivated: nil})
1966
1967 {:ok, _user} =
1968 user
1969 |> Changeset.change()
1970 |> Changeset.put_embed(:info, info_change)
1971 |> User.update_and_set_cache()
1972
1973 Pleroma.Stats.update_stats()
1974
1975 conn = get(conn, "/api/v1/instance")
1976
1977 assert result = json_response(conn, 200)
1978
1979 stats = result["stats"]
1980
1981 assert stats
1982 assert stats["user_count"] == 1
1983 assert stats["status_count"] == 1
1984 assert stats["domain_count"] == 2
1985 end
1986
1987 test "get peers", %{conn: conn} do
1988 insert(:user, %{local: false, nickname: "u@peer1.com"})
1989 insert(:user, %{local: false, nickname: "u@peer2.com"})
1990
1991 Pleroma.Stats.update_stats()
1992
1993 conn = get(conn, "/api/v1/instance/peers")
1994
1995 assert result = json_response(conn, 200)
1996
1997 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
1998 end
1999
2000 test "put settings", %{conn: conn} do
2001 user = insert(:user)
2002
2003 conn =
2004 conn
2005 |> assign(:user, user)
2006 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2007
2008 assert _result = json_response(conn, 200)
2009
2010 user = User.get_cached_by_ap_id(user.ap_id)
2011 assert user.info.settings == %{"programming" => "socks"}
2012 end
2013
2014 describe "pinned statuses" do
2015 setup do
2016 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2017
2018 user = insert(:user)
2019 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2020
2021 [user: user, activity: activity]
2022 end
2023
2024 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2025 {:ok, _} = CommonAPI.pin(activity.id, user)
2026
2027 result =
2028 conn
2029 |> assign(:user, user)
2030 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2031 |> json_response(200)
2032
2033 id_str = to_string(activity.id)
2034
2035 assert [%{"id" => ^id_str, "pinned" => true}] = result
2036 end
2037
2038 test "pin status", %{conn: conn, user: user, activity: activity} do
2039 id_str = to_string(activity.id)
2040
2041 assert %{"id" => ^id_str, "pinned" => true} =
2042 conn
2043 |> assign(:user, user)
2044 |> post("/api/v1/statuses/#{activity.id}/pin")
2045 |> json_response(200)
2046
2047 assert [%{"id" => ^id_str, "pinned" => true}] =
2048 conn
2049 |> assign(:user, user)
2050 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2051 |> json_response(200)
2052 end
2053
2054 test "unpin status", %{conn: conn, user: user, activity: activity} do
2055 {:ok, _} = CommonAPI.pin(activity.id, user)
2056
2057 id_str = to_string(activity.id)
2058 user = refresh_record(user)
2059
2060 assert %{"id" => ^id_str, "pinned" => false} =
2061 conn
2062 |> assign(:user, user)
2063 |> post("/api/v1/statuses/#{activity.id}/unpin")
2064 |> json_response(200)
2065
2066 assert [] =
2067 conn
2068 |> assign(:user, user)
2069 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2070 |> json_response(200)
2071 end
2072
2073 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2074 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2075
2076 id_str_one = to_string(activity_one.id)
2077
2078 assert %{"id" => ^id_str_one, "pinned" => true} =
2079 conn
2080 |> assign(:user, user)
2081 |> post("/api/v1/statuses/#{id_str_one}/pin")
2082 |> json_response(200)
2083
2084 user = refresh_record(user)
2085
2086 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2087 conn
2088 |> assign(:user, user)
2089 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2090 |> json_response(400)
2091 end
2092
2093 test "Status rich-media Card", %{conn: conn, user: user} do
2094 Pleroma.Config.put([:rich_media, :enabled], true)
2095 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2096
2097 response =
2098 conn
2099 |> get("/api/v1/statuses/#{activity.id}/card")
2100 |> json_response(200)
2101
2102 assert response == %{
2103 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2104 "provider_name" => "www.imdb.com",
2105 "provider_url" => "http://www.imdb.com",
2106 "title" => "The Rock",
2107 "type" => "link",
2108 "url" => "http://www.imdb.com/title/tt0117500/",
2109 "description" => nil,
2110 "pleroma" => %{
2111 "opengraph" => %{
2112 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2113 "title" => "The Rock",
2114 "type" => "video.movie",
2115 "url" => "http://www.imdb.com/title/tt0117500/"
2116 }
2117 }
2118 }
2119
2120 # works with private posts
2121 {:ok, activity} =
2122 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2123
2124 response_two =
2125 conn
2126 |> assign(:user, user)
2127 |> get("/api/v1/statuses/#{activity.id}/card")
2128 |> json_response(200)
2129
2130 assert response_two == response
2131
2132 Pleroma.Config.put([:rich_media, :enabled], false)
2133 end
2134 end
2135
2136 test "bookmarks" do
2137 user = insert(:user)
2138 for_user = insert(:user)
2139
2140 {:ok, activity1} =
2141 CommonAPI.post(user, %{
2142 "status" => "heweoo?"
2143 })
2144
2145 {:ok, activity2} =
2146 CommonAPI.post(user, %{
2147 "status" => "heweoo!"
2148 })
2149
2150 response1 =
2151 build_conn()
2152 |> assign(:user, for_user)
2153 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2154
2155 assert json_response(response1, 200)["bookmarked"] == true
2156
2157 response2 =
2158 build_conn()
2159 |> assign(:user, for_user)
2160 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2161
2162 assert json_response(response2, 200)["bookmarked"] == true
2163
2164 bookmarks =
2165 build_conn()
2166 |> assign(:user, for_user)
2167 |> get("/api/v1/bookmarks")
2168
2169 assert [json_response(response2, 200), json_response(response1, 200)] ==
2170 json_response(bookmarks, 200)
2171
2172 response1 =
2173 build_conn()
2174 |> assign(:user, for_user)
2175 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2176
2177 assert json_response(response1, 200)["bookmarked"] == false
2178
2179 bookmarks =
2180 build_conn()
2181 |> assign(:user, for_user)
2182 |> get("/api/v1/bookmarks")
2183
2184 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2185 end
2186
2187 describe "conversation muting" do
2188 setup do
2189 user = insert(:user)
2190 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2191
2192 [user: user, activity: activity]
2193 end
2194
2195 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2196 id_str = to_string(activity.id)
2197
2198 assert %{"id" => ^id_str, "muted" => true} =
2199 conn
2200 |> assign(:user, user)
2201 |> post("/api/v1/statuses/#{activity.id}/mute")
2202 |> json_response(200)
2203 end
2204
2205 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2206 {:ok, _} = CommonAPI.add_mute(user, activity)
2207
2208 id_str = to_string(activity.id)
2209 user = refresh_record(user)
2210
2211 assert %{"id" => ^id_str, "muted" => false} =
2212 conn
2213 |> assign(:user, user)
2214 |> post("/api/v1/statuses/#{activity.id}/unmute")
2215 |> json_response(200)
2216 end
2217 end
2218
2219 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2220 user = insert(:user)
2221
2222 get_old_flavour =
2223 conn
2224 |> assign(:user, user)
2225 |> get("/api/v1/pleroma/flavour")
2226
2227 assert "glitch" == json_response(get_old_flavour, 200)
2228
2229 set_flavour =
2230 conn
2231 |> assign(:user, user)
2232 |> post("/api/v1/pleroma/flavour/vanilla")
2233
2234 assert "vanilla" == json_response(set_flavour, 200)
2235
2236 get_new_flavour =
2237 conn
2238 |> assign(:user, user)
2239 |> post("/api/v1/pleroma/flavour/vanilla")
2240
2241 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2242 end
2243
2244 describe "reports" do
2245 setup do
2246 reporter = insert(:user)
2247 target_user = insert(:user)
2248
2249 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2250
2251 [reporter: reporter, target_user: target_user, activity: activity]
2252 end
2253
2254 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2255 assert %{"action_taken" => false, "id" => _} =
2256 conn
2257 |> assign(:user, reporter)
2258 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2259 |> json_response(200)
2260 end
2261
2262 test "submit a report with statuses and comment", %{
2263 conn: conn,
2264 reporter: reporter,
2265 target_user: target_user,
2266 activity: activity
2267 } do
2268 assert %{"action_taken" => false, "id" => _} =
2269 conn
2270 |> assign(:user, reporter)
2271 |> post("/api/v1/reports", %{
2272 "account_id" => target_user.id,
2273 "status_ids" => [activity.id],
2274 "comment" => "bad status!"
2275 })
2276 |> json_response(200)
2277 end
2278
2279 test "account_id is required", %{
2280 conn: conn,
2281 reporter: reporter,
2282 activity: activity
2283 } do
2284 assert %{"error" => "Valid `account_id` required"} =
2285 conn
2286 |> assign(:user, reporter)
2287 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2288 |> json_response(400)
2289 end
2290
2291 test "comment must be up to the size specified in the config", %{
2292 conn: conn,
2293 reporter: reporter,
2294 target_user: target_user
2295 } do
2296 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2297 comment = String.pad_trailing("a", max_size + 1, "a")
2298
2299 error = %{"error" => "Comment must be up to #{max_size} characters"}
2300
2301 assert ^error =
2302 conn
2303 |> assign(:user, reporter)
2304 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2305 |> json_response(400)
2306 end
2307 end
2308
2309 describe "link headers" do
2310 test "preserves parameters in link headers", %{conn: conn} do
2311 user = insert(:user)
2312 other_user = insert(:user)
2313
2314 {:ok, activity1} =
2315 CommonAPI.post(other_user, %{
2316 "status" => "hi @#{user.nickname}",
2317 "visibility" => "public"
2318 })
2319
2320 {:ok, activity2} =
2321 CommonAPI.post(other_user, %{
2322 "status" => "hi @#{user.nickname}",
2323 "visibility" => "public"
2324 })
2325
2326 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2327 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2328
2329 conn =
2330 conn
2331 |> assign(:user, user)
2332 |> get("/api/v1/notifications", %{media_only: true})
2333
2334 assert [link_header] = get_resp_header(conn, "link")
2335 assert link_header =~ ~r/media_only=true/
2336 assert link_header =~ ~r/since_id=#{notification2.id}/
2337 assert link_header =~ ~r/max_id=#{notification1.id}/
2338 end
2339 end
2340
2341 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2342 # Need to set an old-style integer ID to reproduce the problem
2343 # (these are no longer assigned to new accounts but were preserved
2344 # for existing accounts during the migration to flakeIDs)
2345 user_one = insert(:user, %{id: 1212})
2346 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2347
2348 resp_one =
2349 conn
2350 |> get("/api/v1/accounts/#{user_one.id}")
2351
2352 resp_two =
2353 conn
2354 |> get("/api/v1/accounts/#{user_two.nickname}")
2355
2356 resp_three =
2357 conn
2358 |> get("/api/v1/accounts/#{user_two.id}")
2359
2360 acc_one = json_response(resp_one, 200)
2361 acc_two = json_response(resp_two, 200)
2362 acc_three = json_response(resp_three, 200)
2363 refute acc_one == acc_two
2364 assert acc_two == acc_three
2365 end
2366
2367 describe "custom emoji" do
2368 test "with tags", %{conn: conn} do
2369 [emoji | _body] =
2370 conn
2371 |> get("/api/v1/custom_emojis")
2372 |> json_response(200)
2373
2374 assert Map.has_key?(emoji, "shortcode")
2375 assert Map.has_key?(emoji, "static_url")
2376 assert Map.has_key?(emoji, "tags")
2377 assert is_list(emoji["tags"])
2378 assert Map.has_key?(emoji, "url")
2379 assert Map.has_key?(emoji, "visible_in_picker")
2380 end
2381 end
2382
2383 describe "index/2 redirections" do
2384 setup %{conn: conn} do
2385 session_opts = [
2386 store: :cookie,
2387 key: "_test",
2388 signing_salt: "cooldude"
2389 ]
2390
2391 conn =
2392 conn
2393 |> Plug.Session.call(Plug.Session.init(session_opts))
2394 |> fetch_session()
2395
2396 test_path = "/web/statuses/test"
2397 %{conn: conn, path: test_path}
2398 end
2399
2400 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2401 conn = get(conn, path)
2402
2403 assert conn.status == 302
2404 assert redirected_to(conn) == "/web/login"
2405 end
2406
2407 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2408 token = insert(:oauth_token)
2409
2410 conn =
2411 conn
2412 |> assign(:user, token.user)
2413 |> put_session(:oauth_token, token.token)
2414 |> get(path)
2415
2416 assert conn.status == 200
2417 end
2418
2419 test "saves referer path to session", %{conn: conn, path: path} do
2420 conn = get(conn, path)
2421 return_to = Plug.Conn.get_session(conn, :return_to)
2422
2423 assert return_to == path
2424 end
2425
2426 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2427 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2428 auth = insert(:oauth_authorization, app: app)
2429
2430 conn =
2431 conn
2432 |> put_session(:return_to, path)
2433 |> get("/web/login", %{code: auth.token})
2434
2435 assert conn.status == 302
2436 assert redirected_to(conn) == path
2437 end
2438
2439 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2440 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2441 auth = insert(:oauth_authorization, app: app)
2442
2443 conn = get(conn, "/web/login", %{code: auth.token})
2444
2445 assert conn.status == 302
2446 assert redirected_to(conn) == "/web/getting-started"
2447 end
2448 end
2449
2450 describe "scheduled activities" do
2451 test "creates a scheduled activity", %{conn: conn} do
2452 user = insert(:user)
2453 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2454
2455 conn =
2456 conn
2457 |> assign(:user, user)
2458 |> post("/api/v1/statuses", %{
2459 "status" => "scheduled",
2460 "scheduled_at" => scheduled_at
2461 })
2462
2463 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2464 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2465 assert [] == Repo.all(Activity)
2466 end
2467
2468 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2469 user = insert(:user)
2470 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2471
2472 file = %Plug.Upload{
2473 content_type: "image/jpg",
2474 path: Path.absname("test/fixtures/image.jpg"),
2475 filename: "an_image.jpg"
2476 }
2477
2478 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2479
2480 conn =
2481 conn
2482 |> assign(:user, user)
2483 |> post("/api/v1/statuses", %{
2484 "media_ids" => [to_string(upload.id)],
2485 "status" => "scheduled",
2486 "scheduled_at" => scheduled_at
2487 })
2488
2489 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
2490 assert %{"type" => "image"} = media_attachment
2491 end
2492
2493 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
2494 %{conn: conn} do
2495 user = insert(:user)
2496
2497 scheduled_at =
2498 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
2499
2500 conn =
2501 conn
2502 |> assign(:user, user)
2503 |> post("/api/v1/statuses", %{
2504 "status" => "not scheduled",
2505 "scheduled_at" => scheduled_at
2506 })
2507
2508 assert %{"content" => "not scheduled"} = json_response(conn, 200)
2509 assert [] == Repo.all(ScheduledActivity)
2510 end
2511
2512 test "returns error when daily user limit is exceeded", %{conn: conn} do
2513 user = insert(:user)
2514
2515 today =
2516 NaiveDateTime.utc_now()
2517 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2518 |> NaiveDateTime.to_iso8601()
2519
2520 attrs = %{params: %{}, scheduled_at: today}
2521 {:ok, _} = ScheduledActivity.create(user, attrs)
2522 {:ok, _} = ScheduledActivity.create(user, attrs)
2523
2524 conn =
2525 conn
2526 |> assign(:user, user)
2527 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
2528
2529 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
2530 end
2531
2532 test "returns error when total user limit is exceeded", %{conn: conn} do
2533 user = insert(:user)
2534
2535 today =
2536 NaiveDateTime.utc_now()
2537 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
2538 |> NaiveDateTime.to_iso8601()
2539
2540 tomorrow =
2541 NaiveDateTime.utc_now()
2542 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
2543 |> NaiveDateTime.to_iso8601()
2544
2545 attrs = %{params: %{}, scheduled_at: today}
2546 {:ok, _} = ScheduledActivity.create(user, attrs)
2547 {:ok, _} = ScheduledActivity.create(user, attrs)
2548 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
2549
2550 conn =
2551 conn
2552 |> assign(:user, user)
2553 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
2554
2555 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
2556 end
2557
2558 test "shows scheduled activities", %{conn: conn} do
2559 user = insert(:user)
2560 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
2561 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
2562 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
2563 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
2564
2565 conn =
2566 conn
2567 |> assign(:user, user)
2568
2569 # min_id
2570 conn_res =
2571 conn
2572 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
2573
2574 result = json_response(conn_res, 200)
2575 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2576
2577 # since_id
2578 conn_res =
2579 conn
2580 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
2581
2582 result = json_response(conn_res, 200)
2583 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
2584
2585 # max_id
2586 conn_res =
2587 conn
2588 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
2589
2590 result = json_response(conn_res, 200)
2591 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
2592 end
2593
2594 test "shows a scheduled activity", %{conn: conn} do
2595 user = insert(:user)
2596 scheduled_activity = insert(:scheduled_activity, user: user)
2597
2598 res_conn =
2599 conn
2600 |> assign(:user, user)
2601 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2602
2603 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
2604 assert scheduled_activity_id == scheduled_activity.id |> to_string()
2605
2606 res_conn =
2607 conn
2608 |> assign(:user, user)
2609 |> get("/api/v1/scheduled_statuses/404")
2610
2611 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2612 end
2613
2614 test "updates a scheduled activity", %{conn: conn} do
2615 user = insert(:user)
2616 scheduled_activity = insert(:scheduled_activity, user: user)
2617
2618 new_scheduled_at =
2619 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2620
2621 res_conn =
2622 conn
2623 |> assign(:user, user)
2624 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
2625 scheduled_at: new_scheduled_at
2626 })
2627
2628 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
2629 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
2630
2631 res_conn =
2632 conn
2633 |> assign(:user, user)
2634 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
2635
2636 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2637 end
2638
2639 test "deletes a scheduled activity", %{conn: conn} do
2640 user = insert(:user)
2641 scheduled_activity = insert(:scheduled_activity, user: user)
2642
2643 res_conn =
2644 conn
2645 |> assign(:user, user)
2646 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2647
2648 assert %{} = json_response(res_conn, 200)
2649 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
2650
2651 res_conn =
2652 conn
2653 |> assign(:user, user)
2654 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
2655
2656 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
2657 end
2658 end
2659 end