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