Merge 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 "Conversations", %{conn: conn} do
304 user_one = insert(:user)
305 user_two = insert(:user)
306
307 {:ok, user_two} = User.follow(user_two, user_one)
308
309 {:ok, direct} =
310 CommonAPI.post(user_one, %{
311 "status" => "Hi @#{user_two.nickname}!",
312 "visibility" => "direct"
313 })
314
315 {:ok, _follower_only} =
316 CommonAPI.post(user_one, %{
317 "status" => "Hi @#{user_two.nickname}!",
318 "visibility" => "private"
319 })
320
321 res_conn =
322 conn
323 |> assign(:user, user_one)
324 |> get("/api/v1/conversations")
325
326 assert response = json_response(res_conn, 200)
327
328 assert [
329 %{
330 "id" => res_id,
331 "accounts" => res_accounts,
332 "last_status" => res_last_status,
333 "unread" => unread
334 }
335 ] = response
336
337 assert length(res_accounts) == 2
338 assert is_binary(res_id)
339 assert unread == true
340 assert res_last_status["id"] == direct.id
341
342 # Apparently undocumented API endpoint
343 res_conn =
344 conn
345 |> assign(:user, user_one)
346 |> post("/api/v1/conversations/#{res_id}/read")
347
348 assert response = json_response(res_conn, 200)
349 assert length(response["accounts"]) == 2
350 assert response["last_status"]["id"] == direct.id
351 assert response["unread"] == false
352
353 # (vanilla) Mastodon frontend behaviour
354 res_conn =
355 conn
356 |> assign(:user, user_one)
357 |> get("/api/v1/statuses/#{res_last_status["id"]}/context")
358
359 assert %{"ancestors" => [], "descendants" => []} == json_response(res_conn, 200)
360 end
361
362 test "doesn't include DMs from blocked users", %{conn: conn} do
363 blocker = insert(:user)
364 blocked = insert(:user)
365 user = insert(:user)
366 {:ok, blocker} = User.block(blocker, blocked)
367
368 {:ok, _blocked_direct} =
369 CommonAPI.post(blocked, %{
370 "status" => "Hi @#{blocker.nickname}!",
371 "visibility" => "direct"
372 })
373
374 {:ok, direct} =
375 CommonAPI.post(user, %{
376 "status" => "Hi @#{blocker.nickname}!",
377 "visibility" => "direct"
378 })
379
380 res_conn =
381 conn
382 |> assign(:user, user)
383 |> get("api/v1/timelines/direct")
384
385 [status] = json_response(res_conn, 200)
386 assert status["id"] == direct.id
387 end
388
389 test "replying to a status", %{conn: conn} do
390 user = insert(:user)
391
392 {:ok, replied_to} = TwitterAPI.create_status(user, %{"status" => "cofe"})
393
394 conn =
395 conn
396 |> assign(:user, user)
397 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
398
399 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
400
401 activity = Activity.get_by_id(id)
402
403 assert activity.data["context"] == replied_to.data["context"]
404 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
405 end
406
407 test "posting a status with an invalid in_reply_to_id", %{conn: conn} do
408 user = insert(:user)
409
410 conn =
411 conn
412 |> assign(:user, user)
413 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => ""})
414
415 assert %{"content" => "xD", "id" => id} = json_response(conn, 200)
416
417 activity = Activity.get_by_id(id)
418
419 assert activity
420 end
421
422 test "verify_credentials", %{conn: conn} do
423 user = insert(:user)
424
425 conn =
426 conn
427 |> assign(:user, user)
428 |> get("/api/v1/accounts/verify_credentials")
429
430 assert %{"id" => id, "source" => %{"privacy" => "public"}} = json_response(conn, 200)
431 assert id == to_string(user.id)
432 end
433
434 test "verify_credentials default scope unlisted", %{conn: conn} do
435 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "unlisted"}})
436
437 conn =
438 conn
439 |> assign(:user, user)
440 |> get("/api/v1/accounts/verify_credentials")
441
442 assert %{"id" => id, "source" => %{"privacy" => "unlisted"}} = json_response(conn, 200)
443 assert id == to_string(user.id)
444 end
445
446 test "apps/verify_credentials", %{conn: conn} do
447 token = insert(:oauth_token)
448
449 conn =
450 conn
451 |> assign(:user, token.user)
452 |> assign(:token, token)
453 |> get("/api/v1/apps/verify_credentials")
454
455 app = Repo.preload(token, :app).app
456
457 expected = %{
458 "name" => app.client_name,
459 "website" => app.website,
460 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
461 }
462
463 assert expected == json_response(conn, 200)
464 end
465
466 test "creates an oauth app", %{conn: conn} do
467 user = insert(:user)
468 app_attrs = build(:oauth_app)
469
470 conn =
471 conn
472 |> assign(:user, user)
473 |> post("/api/v1/apps", %{
474 client_name: app_attrs.client_name,
475 redirect_uris: app_attrs.redirect_uris
476 })
477
478 [app] = Repo.all(App)
479
480 expected = %{
481 "name" => app.client_name,
482 "website" => app.website,
483 "client_id" => app.client_id,
484 "client_secret" => app.client_secret,
485 "id" => app.id |> to_string(),
486 "redirect_uri" => app.redirect_uris,
487 "vapid_key" => Push.vapid_config() |> Keyword.get(:public_key)
488 }
489
490 assert expected == json_response(conn, 200)
491 end
492
493 test "get a status", %{conn: conn} do
494 activity = insert(:note_activity)
495
496 conn =
497 conn
498 |> get("/api/v1/statuses/#{activity.id}")
499
500 assert %{"id" => id} = json_response(conn, 200)
501 assert id == to_string(activity.id)
502 end
503
504 describe "deleting a status" do
505 test "when you created it", %{conn: conn} do
506 activity = insert(:note_activity)
507 author = User.get_cached_by_ap_id(activity.data["actor"])
508
509 conn =
510 conn
511 |> assign(:user, author)
512 |> delete("/api/v1/statuses/#{activity.id}")
513
514 assert %{} = json_response(conn, 200)
515
516 refute Activity.get_by_id(activity.id)
517 end
518
519 test "when you didn't create it", %{conn: conn} do
520 activity = insert(:note_activity)
521 user = insert(:user)
522
523 conn =
524 conn
525 |> assign(:user, user)
526 |> delete("/api/v1/statuses/#{activity.id}")
527
528 assert %{"error" => _} = json_response(conn, 403)
529
530 assert Activity.get_by_id(activity.id) == activity
531 end
532
533 test "when you're an admin or moderator", %{conn: conn} do
534 activity1 = insert(:note_activity)
535 activity2 = insert(:note_activity)
536 admin = insert(:user, info: %{is_admin: true})
537 moderator = insert(:user, info: %{is_moderator: true})
538
539 res_conn =
540 conn
541 |> assign(:user, admin)
542 |> delete("/api/v1/statuses/#{activity1.id}")
543
544 assert %{} = json_response(res_conn, 200)
545
546 res_conn =
547 conn
548 |> assign(:user, moderator)
549 |> delete("/api/v1/statuses/#{activity2.id}")
550
551 assert %{} = json_response(res_conn, 200)
552
553 refute Activity.get_by_id(activity1.id)
554 refute Activity.get_by_id(activity2.id)
555 end
556 end
557
558 describe "filters" do
559 test "creating a filter", %{conn: conn} do
560 user = insert(:user)
561
562 filter = %Pleroma.Filter{
563 phrase: "knights",
564 context: ["home"]
565 }
566
567 conn =
568 conn
569 |> assign(:user, user)
570 |> post("/api/v1/filters", %{"phrase" => filter.phrase, context: filter.context})
571
572 assert response = json_response(conn, 200)
573 assert response["phrase"] == filter.phrase
574 assert response["context"] == filter.context
575 assert response["id"] != nil
576 assert response["id"] != ""
577 end
578
579 test "fetching a list of filters", %{conn: conn} do
580 user = insert(:user)
581
582 query_one = %Pleroma.Filter{
583 user_id: user.id,
584 filter_id: 1,
585 phrase: "knights",
586 context: ["home"]
587 }
588
589 query_two = %Pleroma.Filter{
590 user_id: user.id,
591 filter_id: 2,
592 phrase: "who",
593 context: ["home"]
594 }
595
596 {:ok, filter_one} = Pleroma.Filter.create(query_one)
597 {:ok, filter_two} = Pleroma.Filter.create(query_two)
598
599 response =
600 conn
601 |> assign(:user, user)
602 |> get("/api/v1/filters")
603 |> json_response(200)
604
605 assert response ==
606 render_json(
607 FilterView,
608 "filters.json",
609 filters: [filter_two, filter_one]
610 )
611 end
612
613 test "get a filter", %{conn: conn} do
614 user = insert(:user)
615
616 query = %Pleroma.Filter{
617 user_id: user.id,
618 filter_id: 2,
619 phrase: "knight",
620 context: ["home"]
621 }
622
623 {:ok, filter} = Pleroma.Filter.create(query)
624
625 conn =
626 conn
627 |> assign(:user, user)
628 |> get("/api/v1/filters/#{filter.filter_id}")
629
630 assert _response = json_response(conn, 200)
631 end
632
633 test "update a filter", %{conn: conn} do
634 user = insert(:user)
635
636 query = %Pleroma.Filter{
637 user_id: user.id,
638 filter_id: 2,
639 phrase: "knight",
640 context: ["home"]
641 }
642
643 {:ok, _filter} = Pleroma.Filter.create(query)
644
645 new = %Pleroma.Filter{
646 phrase: "nii",
647 context: ["home"]
648 }
649
650 conn =
651 conn
652 |> assign(:user, user)
653 |> put("/api/v1/filters/#{query.filter_id}", %{
654 phrase: new.phrase,
655 context: new.context
656 })
657
658 assert response = json_response(conn, 200)
659 assert response["phrase"] == new.phrase
660 assert response["context"] == new.context
661 end
662
663 test "delete a filter", %{conn: conn} do
664 user = insert(:user)
665
666 query = %Pleroma.Filter{
667 user_id: user.id,
668 filter_id: 2,
669 phrase: "knight",
670 context: ["home"]
671 }
672
673 {:ok, filter} = Pleroma.Filter.create(query)
674
675 conn =
676 conn
677 |> assign(:user, user)
678 |> delete("/api/v1/filters/#{filter.filter_id}")
679
680 assert response = json_response(conn, 200)
681 assert response == %{}
682 end
683 end
684
685 describe "lists" do
686 test "creating a list", %{conn: conn} do
687 user = insert(:user)
688
689 conn =
690 conn
691 |> assign(:user, user)
692 |> post("/api/v1/lists", %{"title" => "cuties"})
693
694 assert %{"title" => title} = json_response(conn, 200)
695 assert title == "cuties"
696 end
697
698 test "adding users to a list", %{conn: conn} do
699 user = insert(:user)
700 other_user = insert(:user)
701 {:ok, list} = Pleroma.List.create("name", user)
702
703 conn =
704 conn
705 |> assign(:user, user)
706 |> post("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
707
708 assert %{} == json_response(conn, 200)
709 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
710 assert following == [other_user.follower_address]
711 end
712
713 test "removing users from a list", %{conn: conn} do
714 user = insert(:user)
715 other_user = insert(:user)
716 third_user = insert(:user)
717 {:ok, list} = Pleroma.List.create("name", user)
718 {:ok, list} = Pleroma.List.follow(list, other_user)
719 {:ok, list} = Pleroma.List.follow(list, third_user)
720
721 conn =
722 conn
723 |> assign(:user, user)
724 |> delete("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
725
726 assert %{} == json_response(conn, 200)
727 %Pleroma.List{following: following} = Pleroma.List.get(list.id, user)
728 assert following == [third_user.follower_address]
729 end
730
731 test "listing users in a list", %{conn: conn} do
732 user = insert(:user)
733 other_user = insert(:user)
734 {:ok, list} = Pleroma.List.create("name", user)
735 {:ok, list} = Pleroma.List.follow(list, other_user)
736
737 conn =
738 conn
739 |> assign(:user, user)
740 |> get("/api/v1/lists/#{list.id}/accounts", %{"account_ids" => [other_user.id]})
741
742 assert [%{"id" => id}] = json_response(conn, 200)
743 assert id == to_string(other_user.id)
744 end
745
746 test "retrieving a list", %{conn: conn} do
747 user = insert(:user)
748 {:ok, list} = Pleroma.List.create("name", user)
749
750 conn =
751 conn
752 |> assign(:user, user)
753 |> get("/api/v1/lists/#{list.id}")
754
755 assert %{"id" => id} = json_response(conn, 200)
756 assert id == to_string(list.id)
757 end
758
759 test "renaming a list", %{conn: conn} do
760 user = insert(:user)
761 {:ok, list} = Pleroma.List.create("name", user)
762
763 conn =
764 conn
765 |> assign(:user, user)
766 |> put("/api/v1/lists/#{list.id}", %{"title" => "newname"})
767
768 assert %{"title" => name} = json_response(conn, 200)
769 assert name == "newname"
770 end
771
772 test "deleting a list", %{conn: conn} do
773 user = insert(:user)
774 {:ok, list} = Pleroma.List.create("name", user)
775
776 conn =
777 conn
778 |> assign(:user, user)
779 |> delete("/api/v1/lists/#{list.id}")
780
781 assert %{} = json_response(conn, 200)
782 assert is_nil(Repo.get(Pleroma.List, list.id))
783 end
784
785 test "list timeline", %{conn: conn} do
786 user = insert(:user)
787 other_user = insert(:user)
788 {:ok, _activity_one} = TwitterAPI.create_status(user, %{"status" => "Marisa is cute."})
789 {:ok, activity_two} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
790 {:ok, list} = Pleroma.List.create("name", user)
791 {:ok, list} = Pleroma.List.follow(list, other_user)
792
793 conn =
794 conn
795 |> assign(:user, user)
796 |> get("/api/v1/timelines/list/#{list.id}")
797
798 assert [%{"id" => id}] = json_response(conn, 200)
799
800 assert id == to_string(activity_two.id)
801 end
802
803 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
804 user = insert(:user)
805 other_user = insert(:user)
806 {:ok, activity_one} = TwitterAPI.create_status(other_user, %{"status" => "Marisa is cute."})
807
808 {:ok, _activity_two} =
809 TwitterAPI.create_status(other_user, %{
810 "status" => "Marisa is cute.",
811 "visibility" => "private"
812 })
813
814 {:ok, list} = Pleroma.List.create("name", user)
815 {:ok, list} = Pleroma.List.follow(list, other_user)
816
817 conn =
818 conn
819 |> assign(:user, user)
820 |> get("/api/v1/timelines/list/#{list.id}")
821
822 assert [%{"id" => id}] = json_response(conn, 200)
823
824 assert id == to_string(activity_one.id)
825 end
826 end
827
828 describe "notifications" do
829 test "list of notifications", %{conn: conn} do
830 user = insert(:user)
831 other_user = insert(:user)
832
833 {:ok, activity} =
834 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
835
836 {:ok, [_notification]} = Notification.create_notifications(activity)
837
838 conn =
839 conn
840 |> assign(:user, user)
841 |> get("/api/v1/notifications")
842
843 expected_response =
844 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
845 user.ap_id
846 }\">@<span>#{user.nickname}</span></a></span>"
847
848 assert [%{"status" => %{"content" => response}} | _rest] = json_response(conn, 200)
849 assert response == expected_response
850 end
851
852 test "getting a single notification", %{conn: conn} do
853 user = insert(:user)
854 other_user = insert(:user)
855
856 {:ok, activity} =
857 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
858
859 {:ok, [notification]} = Notification.create_notifications(activity)
860
861 conn =
862 conn
863 |> assign(:user, user)
864 |> get("/api/v1/notifications/#{notification.id}")
865
866 expected_response =
867 "hi <span class=\"h-card\"><a data-user=\"#{user.id}\" class=\"u-url mention\" href=\"#{
868 user.ap_id
869 }\">@<span>#{user.nickname}</span></a></span>"
870
871 assert %{"status" => %{"content" => response}} = json_response(conn, 200)
872 assert response == expected_response
873 end
874
875 test "dismissing a single notification", %{conn: conn} do
876 user = insert(:user)
877 other_user = insert(:user)
878
879 {:ok, activity} =
880 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
881
882 {:ok, [notification]} = Notification.create_notifications(activity)
883
884 conn =
885 conn
886 |> assign(:user, user)
887 |> post("/api/v1/notifications/dismiss", %{"id" => notification.id})
888
889 assert %{} = json_response(conn, 200)
890 end
891
892 test "clearing all notifications", %{conn: conn} do
893 user = insert(:user)
894 other_user = insert(:user)
895
896 {:ok, activity} =
897 TwitterAPI.create_status(other_user, %{"status" => "hi @#{user.nickname}"})
898
899 {:ok, [_notification]} = Notification.create_notifications(activity)
900
901 conn =
902 conn
903 |> assign(:user, user)
904 |> post("/api/v1/notifications/clear")
905
906 assert %{} = json_response(conn, 200)
907
908 conn =
909 build_conn()
910 |> assign(:user, user)
911 |> get("/api/v1/notifications")
912
913 assert all = json_response(conn, 200)
914 assert all == []
915 end
916
917 test "paginates notifications using min_id, since_id, max_id, and limit", %{conn: conn} do
918 user = insert(:user)
919 other_user = insert(:user)
920
921 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
922 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
923 {:ok, activity3} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
924 {:ok, activity4} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
925
926 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
927 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
928 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
929 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
930
931 conn =
932 conn
933 |> assign(:user, user)
934
935 # min_id
936 conn_res =
937 conn
938 |> get("/api/v1/notifications?limit=2&min_id=#{notification1_id}")
939
940 result = json_response(conn_res, 200)
941 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
942
943 # since_id
944 conn_res =
945 conn
946 |> get("/api/v1/notifications?limit=2&since_id=#{notification1_id}")
947
948 result = json_response(conn_res, 200)
949 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
950
951 # max_id
952 conn_res =
953 conn
954 |> get("/api/v1/notifications?limit=2&max_id=#{notification4_id}")
955
956 result = json_response(conn_res, 200)
957 assert [%{"id" => ^notification3_id}, %{"id" => ^notification2_id}] = result
958 end
959
960 test "filters notifications using exclude_types", %{conn: conn} do
961 user = insert(:user)
962 other_user = insert(:user)
963
964 {:ok, mention_activity} = CommonAPI.post(other_user, %{"status" => "hey @#{user.nickname}"})
965 {:ok, create_activity} = CommonAPI.post(user, %{"status" => "hey"})
966 {:ok, favorite_activity, _} = CommonAPI.favorite(create_activity.id, other_user)
967 {:ok, reblog_activity, _} = CommonAPI.repeat(create_activity.id, other_user)
968 {:ok, _, _, follow_activity} = CommonAPI.follow(other_user, user)
969
970 mention_notification_id =
971 Repo.get_by(Notification, activity_id: mention_activity.id).id |> to_string()
972
973 favorite_notification_id =
974 Repo.get_by(Notification, activity_id: favorite_activity.id).id |> to_string()
975
976 reblog_notification_id =
977 Repo.get_by(Notification, activity_id: reblog_activity.id).id |> to_string()
978
979 follow_notification_id =
980 Repo.get_by(Notification, activity_id: follow_activity.id).id |> to_string()
981
982 conn =
983 conn
984 |> assign(:user, user)
985
986 conn_res =
987 get(conn, "/api/v1/notifications", %{exclude_types: ["mention", "favourite", "reblog"]})
988
989 assert [%{"id" => ^follow_notification_id}] = json_response(conn_res, 200)
990
991 conn_res =
992 get(conn, "/api/v1/notifications", %{exclude_types: ["favourite", "reblog", "follow"]})
993
994 assert [%{"id" => ^mention_notification_id}] = json_response(conn_res, 200)
995
996 conn_res =
997 get(conn, "/api/v1/notifications", %{exclude_types: ["reblog", "follow", "mention"]})
998
999 assert [%{"id" => ^favorite_notification_id}] = json_response(conn_res, 200)
1000
1001 conn_res =
1002 get(conn, "/api/v1/notifications", %{exclude_types: ["follow", "mention", "favourite"]})
1003
1004 assert [%{"id" => ^reblog_notification_id}] = json_response(conn_res, 200)
1005 end
1006
1007 test "destroy multiple", %{conn: conn} do
1008 user = insert(:user)
1009 other_user = insert(:user)
1010
1011 {:ok, activity1} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1012 {:ok, activity2} = CommonAPI.post(other_user, %{"status" => "hi @#{user.nickname}"})
1013 {:ok, activity3} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1014 {:ok, activity4} = CommonAPI.post(user, %{"status" => "hi @#{other_user.nickname}"})
1015
1016 notification1_id = Repo.get_by(Notification, activity_id: activity1.id).id |> to_string()
1017 notification2_id = Repo.get_by(Notification, activity_id: activity2.id).id |> to_string()
1018 notification3_id = Repo.get_by(Notification, activity_id: activity3.id).id |> to_string()
1019 notification4_id = Repo.get_by(Notification, activity_id: activity4.id).id |> to_string()
1020
1021 conn =
1022 conn
1023 |> assign(:user, user)
1024
1025 conn_res =
1026 conn
1027 |> get("/api/v1/notifications")
1028
1029 result = json_response(conn_res, 200)
1030 assert [%{"id" => ^notification2_id}, %{"id" => ^notification1_id}] = result
1031
1032 conn2 =
1033 conn
1034 |> assign(:user, other_user)
1035
1036 conn_res =
1037 conn2
1038 |> get("/api/v1/notifications")
1039
1040 result = json_response(conn_res, 200)
1041 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1042
1043 conn_destroy =
1044 conn
1045 |> delete("/api/v1/notifications/destroy_multiple", %{
1046 "ids" => [notification1_id, notification2_id]
1047 })
1048
1049 assert json_response(conn_destroy, 200) == %{}
1050
1051 conn_res =
1052 conn2
1053 |> get("/api/v1/notifications")
1054
1055 result = json_response(conn_res, 200)
1056 assert [%{"id" => ^notification4_id}, %{"id" => ^notification3_id}] = result
1057 end
1058 end
1059
1060 describe "reblogging" do
1061 test "reblogs and returns the reblogged status", %{conn: conn} do
1062 activity = insert(:note_activity)
1063 user = insert(:user)
1064
1065 conn =
1066 conn
1067 |> assign(:user, user)
1068 |> post("/api/v1/statuses/#{activity.id}/reblog")
1069
1070 assert %{
1071 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1},
1072 "reblogged" => true
1073 } = json_response(conn, 200)
1074
1075 assert to_string(activity.id) == id
1076 end
1077
1078 test "reblogged status for another user", %{conn: conn} do
1079 activity = insert(:note_activity)
1080 user1 = insert(:user)
1081 user2 = insert(:user)
1082 user3 = insert(:user)
1083 CommonAPI.favorite(activity.id, user2)
1084 {:ok, _bookmark} = Pleroma.Bookmark.create(user2.id, activity.id)
1085 {:ok, reblog_activity1, _object} = CommonAPI.repeat(activity.id, user1)
1086 {:ok, _, _object} = CommonAPI.repeat(activity.id, user2)
1087
1088 conn_res =
1089 conn
1090 |> assign(:user, user3)
1091 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1092
1093 assert %{
1094 "reblog" => %{"id" => id, "reblogged" => false, "reblogs_count" => 2},
1095 "reblogged" => false,
1096 "favourited" => false,
1097 "bookmarked" => false
1098 } = json_response(conn_res, 200)
1099
1100 conn_res =
1101 conn
1102 |> assign(:user, user2)
1103 |> get("/api/v1/statuses/#{reblog_activity1.id}")
1104
1105 assert %{
1106 "reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 2},
1107 "reblogged" => true,
1108 "favourited" => true,
1109 "bookmarked" => true
1110 } = json_response(conn_res, 200)
1111
1112 assert to_string(activity.id) == id
1113 end
1114 end
1115
1116 describe "unreblogging" do
1117 test "unreblogs and returns the unreblogged status", %{conn: conn} do
1118 activity = insert(:note_activity)
1119 user = insert(:user)
1120
1121 {:ok, _, _} = CommonAPI.repeat(activity.id, user)
1122
1123 conn =
1124 conn
1125 |> assign(:user, user)
1126 |> post("/api/v1/statuses/#{activity.id}/unreblog")
1127
1128 assert %{"id" => id, "reblogged" => false, "reblogs_count" => 0} = json_response(conn, 200)
1129
1130 assert to_string(activity.id) == id
1131 end
1132 end
1133
1134 describe "favoriting" do
1135 test "favs a status and returns it", %{conn: conn} do
1136 activity = insert(:note_activity)
1137 user = insert(:user)
1138
1139 conn =
1140 conn
1141 |> assign(:user, user)
1142 |> post("/api/v1/statuses/#{activity.id}/favourite")
1143
1144 assert %{"id" => id, "favourites_count" => 1, "favourited" => true} =
1145 json_response(conn, 200)
1146
1147 assert to_string(activity.id) == id
1148 end
1149
1150 test "returns 500 for a wrong id", %{conn: conn} do
1151 user = insert(:user)
1152
1153 resp =
1154 conn
1155 |> assign(:user, user)
1156 |> post("/api/v1/statuses/1/favourite")
1157 |> json_response(500)
1158
1159 assert resp == "Something went wrong"
1160 end
1161 end
1162
1163 describe "unfavoriting" do
1164 test "unfavorites a status and returns it", %{conn: conn} do
1165 activity = insert(:note_activity)
1166 user = insert(:user)
1167
1168 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
1169
1170 conn =
1171 conn
1172 |> assign(:user, user)
1173 |> post("/api/v1/statuses/#{activity.id}/unfavourite")
1174
1175 assert %{"id" => id, "favourites_count" => 0, "favourited" => false} =
1176 json_response(conn, 200)
1177
1178 assert to_string(activity.id) == id
1179 end
1180 end
1181
1182 describe "user timelines" do
1183 test "gets a users statuses", %{conn: conn} do
1184 user_one = insert(:user)
1185 user_two = insert(:user)
1186 user_three = insert(:user)
1187
1188 {:ok, user_three} = User.follow(user_three, user_one)
1189
1190 {:ok, activity} = CommonAPI.post(user_one, %{"status" => "HI!!!"})
1191
1192 {:ok, direct_activity} =
1193 CommonAPI.post(user_one, %{
1194 "status" => "Hi, @#{user_two.nickname}.",
1195 "visibility" => "direct"
1196 })
1197
1198 {:ok, private_activity} =
1199 CommonAPI.post(user_one, %{"status" => "private", "visibility" => "private"})
1200
1201 resp =
1202 conn
1203 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1204
1205 assert [%{"id" => id}] = json_response(resp, 200)
1206 assert id == to_string(activity.id)
1207
1208 resp =
1209 conn
1210 |> assign(:user, user_two)
1211 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1212
1213 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1214 assert id_one == to_string(direct_activity.id)
1215 assert id_two == to_string(activity.id)
1216
1217 resp =
1218 conn
1219 |> assign(:user, user_three)
1220 |> get("/api/v1/accounts/#{user_one.id}/statuses")
1221
1222 assert [%{"id" => id_one}, %{"id" => id_two}] = json_response(resp, 200)
1223 assert id_one == to_string(private_activity.id)
1224 assert id_two == to_string(activity.id)
1225 end
1226
1227 test "unimplemented pinned statuses feature", %{conn: conn} do
1228 note = insert(:note_activity)
1229 user = User.get_cached_by_ap_id(note.data["actor"])
1230
1231 conn =
1232 conn
1233 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
1234
1235 assert json_response(conn, 200) == []
1236 end
1237
1238 test "gets an users media", %{conn: conn} do
1239 note = insert(:note_activity)
1240 user = User.get_cached_by_ap_id(note.data["actor"])
1241
1242 file = %Plug.Upload{
1243 content_type: "image/jpg",
1244 path: Path.absname("test/fixtures/image.jpg"),
1245 filename: "an_image.jpg"
1246 }
1247
1248 media =
1249 TwitterAPI.upload(file, user, "json")
1250 |> Poison.decode!()
1251
1252 {:ok, image_post} =
1253 TwitterAPI.create_status(user, %{"status" => "cofe", "media_ids" => [media["media_id"]]})
1254
1255 conn =
1256 conn
1257 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "true"})
1258
1259 assert [%{"id" => id}] = json_response(conn, 200)
1260 assert id == to_string(image_post.id)
1261
1262 conn =
1263 build_conn()
1264 |> get("/api/v1/accounts/#{user.id}/statuses", %{"only_media" => "1"})
1265
1266 assert [%{"id" => id}] = json_response(conn, 200)
1267 assert id == to_string(image_post.id)
1268 end
1269
1270 test "gets a user's statuses without reblogs", %{conn: conn} do
1271 user = insert(:user)
1272 {:ok, post} = CommonAPI.post(user, %{"status" => "HI!!!"})
1273 {:ok, _, _} = CommonAPI.repeat(post.id, user)
1274
1275 conn =
1276 conn
1277 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "true"})
1278
1279 assert [%{"id" => id}] = json_response(conn, 200)
1280 assert id == to_string(post.id)
1281
1282 conn =
1283 conn
1284 |> get("/api/v1/accounts/#{user.id}/statuses", %{"exclude_reblogs" => "1"})
1285
1286 assert [%{"id" => id}] = json_response(conn, 200)
1287 assert id == to_string(post.id)
1288 end
1289 end
1290
1291 describe "user relationships" do
1292 test "returns the relationships for the current user", %{conn: conn} do
1293 user = insert(:user)
1294 other_user = insert(:user)
1295 {:ok, user} = User.follow(user, other_user)
1296
1297 conn =
1298 conn
1299 |> assign(:user, user)
1300 |> get("/api/v1/accounts/relationships", %{"id" => [other_user.id]})
1301
1302 assert [relationship] = json_response(conn, 200)
1303
1304 assert to_string(other_user.id) == relationship["id"]
1305 end
1306 end
1307
1308 describe "locked accounts" do
1309 test "/api/v1/follow_requests works" do
1310 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1311 other_user = insert(:user)
1312
1313 {:ok, _activity} = ActivityPub.follow(other_user, user)
1314
1315 user = User.get_cached_by_id(user.id)
1316 other_user = User.get_cached_by_id(other_user.id)
1317
1318 assert User.following?(other_user, user) == false
1319
1320 conn =
1321 build_conn()
1322 |> assign(:user, user)
1323 |> get("/api/v1/follow_requests")
1324
1325 assert [relationship] = json_response(conn, 200)
1326 assert to_string(other_user.id) == relationship["id"]
1327 end
1328
1329 test "/api/v1/follow_requests/:id/authorize works" do
1330 user = insert(:user, %{info: %User.Info{locked: true}})
1331 other_user = insert(:user)
1332
1333 {:ok, _activity} = ActivityPub.follow(other_user, user)
1334
1335 user = User.get_cached_by_id(user.id)
1336 other_user = User.get_cached_by_id(other_user.id)
1337
1338 assert User.following?(other_user, user) == false
1339
1340 conn =
1341 build_conn()
1342 |> assign(:user, user)
1343 |> post("/api/v1/follow_requests/#{other_user.id}/authorize")
1344
1345 assert relationship = json_response(conn, 200)
1346 assert to_string(other_user.id) == relationship["id"]
1347
1348 user = User.get_cached_by_id(user.id)
1349 other_user = User.get_cached_by_id(other_user.id)
1350
1351 assert User.following?(other_user, user) == true
1352 end
1353
1354 test "verify_credentials", %{conn: conn} do
1355 user = insert(:user, %{info: %Pleroma.User.Info{default_scope: "private"}})
1356
1357 conn =
1358 conn
1359 |> assign(:user, user)
1360 |> get("/api/v1/accounts/verify_credentials")
1361
1362 assert %{"id" => id, "source" => %{"privacy" => "private"}} = json_response(conn, 200)
1363 assert id == to_string(user.id)
1364 end
1365
1366 test "/api/v1/follow_requests/:id/reject works" do
1367 user = insert(:user, %{info: %Pleroma.User.Info{locked: true}})
1368 other_user = insert(:user)
1369
1370 {:ok, _activity} = ActivityPub.follow(other_user, user)
1371
1372 user = User.get_cached_by_id(user.id)
1373
1374 conn =
1375 build_conn()
1376 |> assign(:user, user)
1377 |> post("/api/v1/follow_requests/#{other_user.id}/reject")
1378
1379 assert relationship = json_response(conn, 200)
1380 assert to_string(other_user.id) == relationship["id"]
1381
1382 user = User.get_cached_by_id(user.id)
1383 other_user = User.get_cached_by_id(other_user.id)
1384
1385 assert User.following?(other_user, user) == false
1386 end
1387 end
1388
1389 test "account fetching", %{conn: conn} do
1390 user = insert(:user)
1391
1392 conn =
1393 conn
1394 |> get("/api/v1/accounts/#{user.id}")
1395
1396 assert %{"id" => id} = json_response(conn, 200)
1397 assert id == to_string(user.id)
1398
1399 conn =
1400 build_conn()
1401 |> get("/api/v1/accounts/-1")
1402
1403 assert %{"error" => "Can't find user"} = json_response(conn, 404)
1404 end
1405
1406 test "account fetching also works nickname", %{conn: conn} do
1407 user = insert(:user)
1408
1409 conn =
1410 conn
1411 |> get("/api/v1/accounts/#{user.nickname}")
1412
1413 assert %{"id" => id} = json_response(conn, 200)
1414 assert id == user.id
1415 end
1416
1417 test "media upload", %{conn: conn} do
1418 file = %Plug.Upload{
1419 content_type: "image/jpg",
1420 path: Path.absname("test/fixtures/image.jpg"),
1421 filename: "an_image.jpg"
1422 }
1423
1424 desc = "Description of the image"
1425
1426 user = insert(:user)
1427
1428 conn =
1429 conn
1430 |> assign(:user, user)
1431 |> post("/api/v1/media", %{"file" => file, "description" => desc})
1432
1433 assert media = json_response(conn, 200)
1434
1435 assert media["type"] == "image"
1436 assert media["description"] == desc
1437 assert media["id"]
1438
1439 object = Repo.get(Object, media["id"])
1440 assert object.data["actor"] == User.ap_id(user)
1441 end
1442
1443 test "hashtag timeline", %{conn: conn} do
1444 following = insert(:user)
1445
1446 capture_log(fn ->
1447 {:ok, activity} = TwitterAPI.create_status(following, %{"status" => "test #2hu"})
1448
1449 {:ok, [_activity]} =
1450 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
1451
1452 nconn =
1453 conn
1454 |> get("/api/v1/timelines/tag/2hu")
1455
1456 assert [%{"id" => id}] = json_response(nconn, 200)
1457
1458 assert id == to_string(activity.id)
1459
1460 # works for different capitalization too
1461 nconn =
1462 conn
1463 |> get("/api/v1/timelines/tag/2HU")
1464
1465 assert [%{"id" => id}] = json_response(nconn, 200)
1466
1467 assert id == to_string(activity.id)
1468 end)
1469 end
1470
1471 test "multi-hashtag timeline", %{conn: conn} do
1472 user = insert(:user)
1473
1474 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
1475 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
1476 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
1477
1478 any_test =
1479 conn
1480 |> get("/api/v1/timelines/tag/test", %{"any" => ["test1"]})
1481
1482 [status_none, status_test1, status_test] = json_response(any_test, 200)
1483
1484 assert to_string(activity_test.id) == status_test["id"]
1485 assert to_string(activity_test1.id) == status_test1["id"]
1486 assert to_string(activity_none.id) == status_none["id"]
1487
1488 restricted_test =
1489 conn
1490 |> get("/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
1491
1492 assert [status_test1] == json_response(restricted_test, 200)
1493
1494 all_test = conn |> get("/api/v1/timelines/tag/test", %{"all" => ["none"]})
1495
1496 assert [status_none] == json_response(all_test, 200)
1497 end
1498
1499 test "getting followers", %{conn: conn} do
1500 user = insert(:user)
1501 other_user = insert(:user)
1502 {:ok, user} = User.follow(user, other_user)
1503
1504 conn =
1505 conn
1506 |> get("/api/v1/accounts/#{other_user.id}/followers")
1507
1508 assert [%{"id" => id}] = json_response(conn, 200)
1509 assert id == to_string(user.id)
1510 end
1511
1512 test "getting followers, hide_followers", %{conn: conn} do
1513 user = insert(:user)
1514 other_user = insert(:user, %{info: %{hide_followers: true}})
1515 {:ok, _user} = User.follow(user, other_user)
1516
1517 conn =
1518 conn
1519 |> get("/api/v1/accounts/#{other_user.id}/followers")
1520
1521 assert [] == json_response(conn, 200)
1522 end
1523
1524 test "getting followers, hide_followers, same user requesting", %{conn: conn} do
1525 user = insert(:user)
1526 other_user = insert(:user, %{info: %{hide_followers: true}})
1527 {:ok, _user} = User.follow(user, other_user)
1528
1529 conn =
1530 conn
1531 |> assign(:user, other_user)
1532 |> get("/api/v1/accounts/#{other_user.id}/followers")
1533
1534 refute [] == json_response(conn, 200)
1535 end
1536
1537 test "getting followers, pagination", %{conn: conn} do
1538 user = insert(:user)
1539 follower1 = insert(:user)
1540 follower2 = insert(:user)
1541 follower3 = insert(:user)
1542 {:ok, _} = User.follow(follower1, user)
1543 {:ok, _} = User.follow(follower2, user)
1544 {:ok, _} = User.follow(follower3, user)
1545
1546 conn =
1547 conn
1548 |> assign(:user, user)
1549
1550 res_conn =
1551 conn
1552 |> get("/api/v1/accounts/#{user.id}/followers?since_id=#{follower1.id}")
1553
1554 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1555 assert id3 == follower3.id
1556 assert id2 == follower2.id
1557
1558 res_conn =
1559 conn
1560 |> get("/api/v1/accounts/#{user.id}/followers?max_id=#{follower3.id}")
1561
1562 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1563 assert id2 == follower2.id
1564 assert id1 == follower1.id
1565
1566 res_conn =
1567 conn
1568 |> get("/api/v1/accounts/#{user.id}/followers?limit=1&max_id=#{follower3.id}")
1569
1570 assert [%{"id" => id2}] = json_response(res_conn, 200)
1571 assert id2 == follower2.id
1572
1573 assert [link_header] = get_resp_header(res_conn, "link")
1574 assert link_header =~ ~r/min_id=#{follower2.id}/
1575 assert link_header =~ ~r/max_id=#{follower2.id}/
1576 end
1577
1578 test "getting following", %{conn: conn} do
1579 user = insert(:user)
1580 other_user = insert(:user)
1581 {:ok, user} = User.follow(user, other_user)
1582
1583 conn =
1584 conn
1585 |> get("/api/v1/accounts/#{user.id}/following")
1586
1587 assert [%{"id" => id}] = json_response(conn, 200)
1588 assert id == to_string(other_user.id)
1589 end
1590
1591 test "getting following, hide_follows", %{conn: conn} do
1592 user = insert(:user, %{info: %{hide_follows: true}})
1593 other_user = insert(:user)
1594 {:ok, user} = User.follow(user, other_user)
1595
1596 conn =
1597 conn
1598 |> get("/api/v1/accounts/#{user.id}/following")
1599
1600 assert [] == json_response(conn, 200)
1601 end
1602
1603 test "getting following, hide_follows, same user requesting", %{conn: conn} do
1604 user = insert(:user, %{info: %{hide_follows: true}})
1605 other_user = insert(:user)
1606 {:ok, user} = User.follow(user, other_user)
1607
1608 conn =
1609 conn
1610 |> assign(:user, user)
1611 |> get("/api/v1/accounts/#{user.id}/following")
1612
1613 refute [] == json_response(conn, 200)
1614 end
1615
1616 test "getting following, pagination", %{conn: conn} do
1617 user = insert(:user)
1618 following1 = insert(:user)
1619 following2 = insert(:user)
1620 following3 = insert(:user)
1621 {:ok, _} = User.follow(user, following1)
1622 {:ok, _} = User.follow(user, following2)
1623 {:ok, _} = User.follow(user, following3)
1624
1625 conn =
1626 conn
1627 |> assign(:user, user)
1628
1629 res_conn =
1630 conn
1631 |> get("/api/v1/accounts/#{user.id}/following?since_id=#{following1.id}")
1632
1633 assert [%{"id" => id3}, %{"id" => id2}] = json_response(res_conn, 200)
1634 assert id3 == following3.id
1635 assert id2 == following2.id
1636
1637 res_conn =
1638 conn
1639 |> get("/api/v1/accounts/#{user.id}/following?max_id=#{following3.id}")
1640
1641 assert [%{"id" => id2}, %{"id" => id1}] = json_response(res_conn, 200)
1642 assert id2 == following2.id
1643 assert id1 == following1.id
1644
1645 res_conn =
1646 conn
1647 |> get("/api/v1/accounts/#{user.id}/following?limit=1&max_id=#{following3.id}")
1648
1649 assert [%{"id" => id2}] = json_response(res_conn, 200)
1650 assert id2 == following2.id
1651
1652 assert [link_header] = get_resp_header(res_conn, "link")
1653 assert link_header =~ ~r/min_id=#{following2.id}/
1654 assert link_header =~ ~r/max_id=#{following2.id}/
1655 end
1656
1657 test "following / unfollowing a user", %{conn: conn} do
1658 user = insert(:user)
1659 other_user = insert(:user)
1660
1661 conn =
1662 conn
1663 |> assign(:user, user)
1664 |> post("/api/v1/accounts/#{other_user.id}/follow")
1665
1666 assert %{"id" => _id, "following" => true} = json_response(conn, 200)
1667
1668 user = User.get_cached_by_id(user.id)
1669
1670 conn =
1671 build_conn()
1672 |> assign(:user, user)
1673 |> post("/api/v1/accounts/#{other_user.id}/unfollow")
1674
1675 assert %{"id" => _id, "following" => false} = json_response(conn, 200)
1676
1677 user = User.get_cached_by_id(user.id)
1678
1679 conn =
1680 build_conn()
1681 |> assign(:user, user)
1682 |> post("/api/v1/follows", %{"uri" => other_user.nickname})
1683
1684 assert %{"id" => id} = json_response(conn, 200)
1685 assert id == to_string(other_user.id)
1686 end
1687
1688 test "following without reblogs" do
1689 follower = insert(:user)
1690 followed = insert(:user)
1691 other_user = insert(:user)
1692
1693 conn =
1694 build_conn()
1695 |> assign(:user, follower)
1696 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=false")
1697
1698 assert %{"showing_reblogs" => false} = json_response(conn, 200)
1699
1700 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "hey"})
1701 {:ok, reblog, _} = CommonAPI.repeat(activity.id, followed)
1702
1703 conn =
1704 build_conn()
1705 |> assign(:user, User.get_cached_by_id(follower.id))
1706 |> get("/api/v1/timelines/home")
1707
1708 assert [] == json_response(conn, 200)
1709
1710 conn =
1711 build_conn()
1712 |> assign(:user, follower)
1713 |> post("/api/v1/accounts/#{followed.id}/follow?reblogs=true")
1714
1715 assert %{"showing_reblogs" => true} = json_response(conn, 200)
1716
1717 conn =
1718 build_conn()
1719 |> assign(:user, User.get_cached_by_id(follower.id))
1720 |> get("/api/v1/timelines/home")
1721
1722 expected_activity_id = reblog.id
1723 assert [%{"id" => ^expected_activity_id}] = json_response(conn, 200)
1724 end
1725
1726 test "following / unfollowing errors" do
1727 user = insert(:user)
1728
1729 conn =
1730 build_conn()
1731 |> assign(:user, user)
1732
1733 # self follow
1734 conn_res = post(conn, "/api/v1/accounts/#{user.id}/follow")
1735 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1736
1737 # self unfollow
1738 user = User.get_cached_by_id(user.id)
1739 conn_res = post(conn, "/api/v1/accounts/#{user.id}/unfollow")
1740 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1741
1742 # self follow via uri
1743 user = User.get_cached_by_id(user.id)
1744 conn_res = post(conn, "/api/v1/follows", %{"uri" => user.nickname})
1745 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1746
1747 # follow non existing user
1748 conn_res = post(conn, "/api/v1/accounts/doesntexist/follow")
1749 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1750
1751 # follow non existing user via uri
1752 conn_res = post(conn, "/api/v1/follows", %{"uri" => "doesntexist"})
1753 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1754
1755 # unfollow non existing user
1756 conn_res = post(conn, "/api/v1/accounts/doesntexist/unfollow")
1757 assert %{"error" => "Record not found"} = json_response(conn_res, 404)
1758 end
1759
1760 test "muting / unmuting a user", %{conn: conn} do
1761 user = insert(:user)
1762 other_user = insert(:user)
1763
1764 conn =
1765 conn
1766 |> assign(:user, user)
1767 |> post("/api/v1/accounts/#{other_user.id}/mute")
1768
1769 assert %{"id" => _id, "muting" => true} = json_response(conn, 200)
1770
1771 user = User.get_cached_by_id(user.id)
1772
1773 conn =
1774 build_conn()
1775 |> assign(:user, user)
1776 |> post("/api/v1/accounts/#{other_user.id}/unmute")
1777
1778 assert %{"id" => _id, "muting" => false} = json_response(conn, 200)
1779 end
1780
1781 test "subscribing / unsubscribing to a user", %{conn: conn} do
1782 user = insert(:user)
1783 subscription_target = insert(:user)
1784
1785 conn =
1786 conn
1787 |> assign(:user, user)
1788 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/subscribe")
1789
1790 assert %{"id" => _id, "subscribing" => true} = json_response(conn, 200)
1791
1792 conn =
1793 build_conn()
1794 |> assign(:user, user)
1795 |> post("/api/v1/pleroma/accounts/#{subscription_target.id}/unsubscribe")
1796
1797 assert %{"id" => _id, "subscribing" => false} = json_response(conn, 200)
1798 end
1799
1800 test "getting a list of mutes", %{conn: conn} do
1801 user = insert(:user)
1802 other_user = insert(:user)
1803
1804 {:ok, user} = User.mute(user, other_user)
1805
1806 conn =
1807 conn
1808 |> assign(:user, user)
1809 |> get("/api/v1/mutes")
1810
1811 other_user_id = to_string(other_user.id)
1812 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1813 end
1814
1815 test "blocking / unblocking a user", %{conn: conn} do
1816 user = insert(:user)
1817 other_user = insert(:user)
1818
1819 conn =
1820 conn
1821 |> assign(:user, user)
1822 |> post("/api/v1/accounts/#{other_user.id}/block")
1823
1824 assert %{"id" => _id, "blocking" => true} = json_response(conn, 200)
1825
1826 user = User.get_cached_by_id(user.id)
1827
1828 conn =
1829 build_conn()
1830 |> assign(:user, user)
1831 |> post("/api/v1/accounts/#{other_user.id}/unblock")
1832
1833 assert %{"id" => _id, "blocking" => false} = json_response(conn, 200)
1834 end
1835
1836 test "getting a list of blocks", %{conn: conn} do
1837 user = insert(:user)
1838 other_user = insert(:user)
1839
1840 {:ok, user} = User.block(user, other_user)
1841
1842 conn =
1843 conn
1844 |> assign(:user, user)
1845 |> get("/api/v1/blocks")
1846
1847 other_user_id = to_string(other_user.id)
1848 assert [%{"id" => ^other_user_id}] = json_response(conn, 200)
1849 end
1850
1851 test "blocking / unblocking a domain", %{conn: conn} do
1852 user = insert(:user)
1853 other_user = insert(:user, %{ap_id: "https://dogwhistle.zone/@pundit"})
1854
1855 conn =
1856 conn
1857 |> assign(:user, user)
1858 |> post("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1859
1860 assert %{} = json_response(conn, 200)
1861 user = User.get_cached_by_ap_id(user.ap_id)
1862 assert User.blocks?(user, other_user)
1863
1864 conn =
1865 build_conn()
1866 |> assign(:user, user)
1867 |> delete("/api/v1/domain_blocks", %{"domain" => "dogwhistle.zone"})
1868
1869 assert %{} = json_response(conn, 200)
1870 user = User.get_cached_by_ap_id(user.ap_id)
1871 refute User.blocks?(user, other_user)
1872 end
1873
1874 test "getting a list of domain blocks", %{conn: conn} do
1875 user = insert(:user)
1876
1877 {:ok, user} = User.block_domain(user, "bad.site")
1878 {:ok, user} = User.block_domain(user, "even.worse.site")
1879
1880 conn =
1881 conn
1882 |> assign(:user, user)
1883 |> get("/api/v1/domain_blocks")
1884
1885 domain_blocks = json_response(conn, 200)
1886
1887 assert "bad.site" in domain_blocks
1888 assert "even.worse.site" in domain_blocks
1889 end
1890
1891 test "unimplemented follow_requests, blocks, domain blocks" do
1892 user = insert(:user)
1893
1894 ["blocks", "domain_blocks", "follow_requests"]
1895 |> Enum.each(fn endpoint ->
1896 conn =
1897 build_conn()
1898 |> assign(:user, user)
1899 |> get("/api/v1/#{endpoint}")
1900
1901 assert [] = json_response(conn, 200)
1902 end)
1903 end
1904
1905 test "account search", %{conn: conn} do
1906 user = insert(:user)
1907 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1908 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1909
1910 results =
1911 conn
1912 |> assign(:user, user)
1913 |> get("/api/v1/accounts/search", %{"q" => "shp"})
1914 |> json_response(200)
1915
1916 result_ids = for result <- results, do: result["acct"]
1917
1918 assert user_two.nickname in result_ids
1919 assert user_three.nickname in result_ids
1920
1921 results =
1922 conn
1923 |> assign(:user, user)
1924 |> get("/api/v1/accounts/search", %{"q" => "2hu"})
1925 |> json_response(200)
1926
1927 result_ids = for result <- results, do: result["acct"]
1928
1929 assert user_three.nickname in result_ids
1930 end
1931
1932 test "search", %{conn: conn} do
1933 user = insert(:user)
1934 user_two = insert(:user, %{nickname: "shp@shitposter.club"})
1935 user_three = insert(:user, %{nickname: "shp@heldscal.la", name: "I love 2hu"})
1936
1937 {:ok, activity} = CommonAPI.post(user, %{"status" => "This is about 2hu"})
1938
1939 {:ok, _activity} =
1940 CommonAPI.post(user, %{
1941 "status" => "This is about 2hu, but private",
1942 "visibility" => "private"
1943 })
1944
1945 {:ok, _} = CommonAPI.post(user_two, %{"status" => "This isn't"})
1946
1947 conn =
1948 conn
1949 |> get("/api/v1/search", %{"q" => "2hu"})
1950
1951 assert results = json_response(conn, 200)
1952
1953 [account | _] = results["accounts"]
1954 assert account["id"] == to_string(user_three.id)
1955
1956 assert results["hashtags"] == []
1957
1958 [status] = results["statuses"]
1959 assert status["id"] == to_string(activity.id)
1960 end
1961
1962 test "search fetches remote statuses", %{conn: conn} do
1963 capture_log(fn ->
1964 conn =
1965 conn
1966 |> get("/api/v1/search", %{"q" => "https://shitposter.club/notice/2827873"})
1967
1968 assert results = json_response(conn, 200)
1969
1970 [status] = results["statuses"]
1971 assert status["uri"] == "tag:shitposter.club,2017-05-05:noticeId=2827873:objectType=comment"
1972 end)
1973 end
1974
1975 test "search doesn't show statuses that it shouldn't", %{conn: conn} do
1976 {:ok, activity} =
1977 CommonAPI.post(insert(:user), %{
1978 "status" => "This is about 2hu, but private",
1979 "visibility" => "private"
1980 })
1981
1982 capture_log(fn ->
1983 conn =
1984 conn
1985 |> get("/api/v1/search", %{"q" => Object.normalize(activity).data["id"]})
1986
1987 assert results = json_response(conn, 200)
1988
1989 [] = results["statuses"]
1990 end)
1991 end
1992
1993 test "search fetches remote accounts", %{conn: conn} do
1994 conn =
1995 conn
1996 |> get("/api/v1/search", %{"q" => "shp@social.heldscal.la", "resolve" => "true"})
1997
1998 assert results = json_response(conn, 200)
1999 [account] = results["accounts"]
2000 assert account["acct"] == "shp@social.heldscal.la"
2001 end
2002
2003 test "returns the favorites of a user", %{conn: conn} do
2004 user = insert(:user)
2005 other_user = insert(:user)
2006
2007 {:ok, _} = CommonAPI.post(other_user, %{"status" => "bla"})
2008 {:ok, activity} = CommonAPI.post(other_user, %{"status" => "traps are happy"})
2009
2010 {:ok, _, _} = CommonAPI.favorite(activity.id, user)
2011
2012 first_conn =
2013 conn
2014 |> assign(:user, user)
2015 |> get("/api/v1/favourites")
2016
2017 assert [status] = json_response(first_conn, 200)
2018 assert status["id"] == to_string(activity.id)
2019
2020 assert [{"link", _link_header}] =
2021 Enum.filter(first_conn.resp_headers, fn element -> match?({"link", _}, element) end)
2022
2023 # Honours query params
2024 {:ok, second_activity} =
2025 CommonAPI.post(other_user, %{
2026 "status" =>
2027 "Trees Are Never Sad Look At Them Every Once In Awhile They're Quite Beautiful."
2028 })
2029
2030 {:ok, _, _} = CommonAPI.favorite(second_activity.id, user)
2031
2032 last_like = status["id"]
2033
2034 second_conn =
2035 conn
2036 |> assign(:user, user)
2037 |> get("/api/v1/favourites?since_id=#{last_like}")
2038
2039 assert [second_status] = json_response(second_conn, 200)
2040 assert second_status["id"] == to_string(second_activity.id)
2041
2042 third_conn =
2043 conn
2044 |> assign(:user, user)
2045 |> get("/api/v1/favourites?limit=0")
2046
2047 assert [] = json_response(third_conn, 200)
2048 end
2049
2050 describe "getting favorites timeline of specified user" do
2051 setup do
2052 [current_user, user] = insert_pair(:user, %{info: %{hide_favorites: false}})
2053 [current_user: current_user, user: user]
2054 end
2055
2056 test "returns list of statuses favorited by specified user", %{
2057 conn: conn,
2058 current_user: current_user,
2059 user: user
2060 } do
2061 [activity | _] = insert_pair(:note_activity)
2062 CommonAPI.favorite(activity.id, user)
2063
2064 response =
2065 conn
2066 |> assign(:user, current_user)
2067 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2068 |> json_response(:ok)
2069
2070 [like] = response
2071
2072 assert length(response) == 1
2073 assert like["id"] == activity.id
2074 end
2075
2076 test "returns favorites for specified user_id when user is not logged in", %{
2077 conn: conn,
2078 user: user
2079 } do
2080 activity = insert(:note_activity)
2081 CommonAPI.favorite(activity.id, user)
2082
2083 response =
2084 conn
2085 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2086 |> json_response(:ok)
2087
2088 assert length(response) == 1
2089 end
2090
2091 test "returns favorited DM only when user is logged in and he is one of recipients", %{
2092 conn: conn,
2093 current_user: current_user,
2094 user: user
2095 } do
2096 {:ok, direct} =
2097 CommonAPI.post(current_user, %{
2098 "status" => "Hi @#{user.nickname}!",
2099 "visibility" => "direct"
2100 })
2101
2102 CommonAPI.favorite(direct.id, user)
2103
2104 response =
2105 conn
2106 |> assign(:user, current_user)
2107 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2108 |> json_response(:ok)
2109
2110 assert length(response) == 1
2111
2112 anonymous_response =
2113 conn
2114 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2115 |> json_response(:ok)
2116
2117 assert length(anonymous_response) == 0
2118 end
2119
2120 test "does not return others' favorited DM when user is not one of recipients", %{
2121 conn: conn,
2122 current_user: current_user,
2123 user: user
2124 } do
2125 user_two = insert(:user)
2126
2127 {:ok, direct} =
2128 CommonAPI.post(user_two, %{
2129 "status" => "Hi @#{user.nickname}!",
2130 "visibility" => "direct"
2131 })
2132
2133 CommonAPI.favorite(direct.id, user)
2134
2135 response =
2136 conn
2137 |> assign(:user, current_user)
2138 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2139 |> json_response(:ok)
2140
2141 assert length(response) == 0
2142 end
2143
2144 test "paginates favorites using since_id and max_id", %{
2145 conn: conn,
2146 current_user: current_user,
2147 user: user
2148 } do
2149 activities = insert_list(10, :note_activity)
2150
2151 Enum.each(activities, fn activity ->
2152 CommonAPI.favorite(activity.id, user)
2153 end)
2154
2155 third_activity = Enum.at(activities, 2)
2156 seventh_activity = Enum.at(activities, 6)
2157
2158 response =
2159 conn
2160 |> assign(:user, current_user)
2161 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{
2162 since_id: third_activity.id,
2163 max_id: seventh_activity.id
2164 })
2165 |> json_response(:ok)
2166
2167 assert length(response) == 3
2168 refute third_activity in response
2169 refute seventh_activity in response
2170 end
2171
2172 test "limits favorites using limit parameter", %{
2173 conn: conn,
2174 current_user: current_user,
2175 user: user
2176 } do
2177 7
2178 |> insert_list(:note_activity)
2179 |> Enum.each(fn activity ->
2180 CommonAPI.favorite(activity.id, user)
2181 end)
2182
2183 response =
2184 conn
2185 |> assign(:user, current_user)
2186 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites", %{limit: "3"})
2187 |> json_response(:ok)
2188
2189 assert length(response) == 3
2190 end
2191
2192 test "returns empty response when user does not have any favorited statuses", %{
2193 conn: conn,
2194 current_user: current_user,
2195 user: user
2196 } do
2197 response =
2198 conn
2199 |> assign(:user, current_user)
2200 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2201 |> json_response(:ok)
2202
2203 assert Enum.empty?(response)
2204 end
2205
2206 test "returns 404 error when specified user is not exist", %{conn: conn} do
2207 conn = get(conn, "/api/v1/pleroma/accounts/test/favourites")
2208
2209 assert json_response(conn, 404) == %{"error" => "Record not found"}
2210 end
2211
2212 test "returns 403 error when user has hidden own favorites", %{
2213 conn: conn,
2214 current_user: current_user
2215 } do
2216 user = insert(:user, %{info: %{hide_favorites: true}})
2217 activity = insert(:note_activity)
2218 CommonAPI.favorite(activity.id, user)
2219
2220 conn =
2221 conn
2222 |> assign(:user, current_user)
2223 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2224
2225 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2226 end
2227
2228 test "hides favorites for new users by default", %{conn: conn, current_user: current_user} do
2229 user = insert(:user)
2230 activity = insert(:note_activity)
2231 CommonAPI.favorite(activity.id, user)
2232
2233 conn =
2234 conn
2235 |> assign(:user, current_user)
2236 |> get("/api/v1/pleroma/accounts/#{user.id}/favourites")
2237
2238 assert user.info.hide_favorites
2239 assert json_response(conn, 403) == %{"error" => "Can't get favorites"}
2240 end
2241 end
2242
2243 describe "updating credentials" do
2244 test "updates the user's bio", %{conn: conn} do
2245 user = insert(:user)
2246 user2 = insert(:user)
2247
2248 conn =
2249 conn
2250 |> assign(:user, user)
2251 |> patch("/api/v1/accounts/update_credentials", %{
2252 "note" => "I drink #cofe with @#{user2.nickname}"
2253 })
2254
2255 assert user = json_response(conn, 200)
2256
2257 assert user["note"] ==
2258 ~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=") <>
2259 user2.id <>
2260 ~s(" class="u-url mention" href=") <>
2261 user2.ap_id <> ~s(">@<span>) <> user2.nickname <> ~s(</span></a></span>)
2262 end
2263
2264 test "updates the user's locking status", %{conn: conn} do
2265 user = insert(:user)
2266
2267 conn =
2268 conn
2269 |> assign(:user, user)
2270 |> patch("/api/v1/accounts/update_credentials", %{locked: "true"})
2271
2272 assert user = json_response(conn, 200)
2273 assert user["locked"] == true
2274 end
2275
2276 test "updates the user's default scope", %{conn: conn} do
2277 user = insert(:user)
2278
2279 conn =
2280 conn
2281 |> assign(:user, user)
2282 |> patch("/api/v1/accounts/update_credentials", %{default_scope: "cofe"})
2283
2284 assert user = json_response(conn, 200)
2285 assert user["source"]["privacy"] == "cofe"
2286 end
2287
2288 test "updates the user's hide_followers status", %{conn: conn} do
2289 user = insert(:user)
2290
2291 conn =
2292 conn
2293 |> assign(:user, user)
2294 |> patch("/api/v1/accounts/update_credentials", %{hide_followers: "true"})
2295
2296 assert user = json_response(conn, 200)
2297 assert user["pleroma"]["hide_followers"] == true
2298 end
2299
2300 test "updates the user's hide_follows status", %{conn: conn} do
2301 user = insert(:user)
2302
2303 conn =
2304 conn
2305 |> assign(:user, user)
2306 |> patch("/api/v1/accounts/update_credentials", %{hide_follows: "true"})
2307
2308 assert user = json_response(conn, 200)
2309 assert user["pleroma"]["hide_follows"] == true
2310 end
2311
2312 test "updates the user's hide_favorites status", %{conn: conn} do
2313 user = insert(:user)
2314
2315 conn =
2316 conn
2317 |> assign(:user, user)
2318 |> patch("/api/v1/accounts/update_credentials", %{hide_favorites: "true"})
2319
2320 assert user = json_response(conn, 200)
2321 assert user["pleroma"]["hide_favorites"] == true
2322 end
2323
2324 test "updates the user's show_role status", %{conn: conn} do
2325 user = insert(:user)
2326
2327 conn =
2328 conn
2329 |> assign(:user, user)
2330 |> patch("/api/v1/accounts/update_credentials", %{show_role: "false"})
2331
2332 assert user = json_response(conn, 200)
2333 assert user["source"]["pleroma"]["show_role"] == false
2334 end
2335
2336 test "updates the user's no_rich_text status", %{conn: conn} do
2337 user = insert(:user)
2338
2339 conn =
2340 conn
2341 |> assign(:user, user)
2342 |> patch("/api/v1/accounts/update_credentials", %{no_rich_text: "true"})
2343
2344 assert user = json_response(conn, 200)
2345 assert user["source"]["pleroma"]["no_rich_text"] == true
2346 end
2347
2348 test "updates the user's name", %{conn: conn} do
2349 user = insert(:user)
2350
2351 conn =
2352 conn
2353 |> assign(:user, user)
2354 |> patch("/api/v1/accounts/update_credentials", %{"display_name" => "markorepairs"})
2355
2356 assert user = json_response(conn, 200)
2357 assert user["display_name"] == "markorepairs"
2358 end
2359
2360 test "updates the user's avatar", %{conn: conn} do
2361 user = insert(:user)
2362
2363 new_avatar = %Plug.Upload{
2364 content_type: "image/jpg",
2365 path: Path.absname("test/fixtures/image.jpg"),
2366 filename: "an_image.jpg"
2367 }
2368
2369 conn =
2370 conn
2371 |> assign(:user, user)
2372 |> patch("/api/v1/accounts/update_credentials", %{"avatar" => new_avatar})
2373
2374 assert user_response = json_response(conn, 200)
2375 assert user_response["avatar"] != User.avatar_url(user)
2376 end
2377
2378 test "updates the user's banner", %{conn: conn} do
2379 user = insert(:user)
2380
2381 new_header = %Plug.Upload{
2382 content_type: "image/jpg",
2383 path: Path.absname("test/fixtures/image.jpg"),
2384 filename: "an_image.jpg"
2385 }
2386
2387 conn =
2388 conn
2389 |> assign(:user, user)
2390 |> patch("/api/v1/accounts/update_credentials", %{"header" => new_header})
2391
2392 assert user_response = json_response(conn, 200)
2393 assert user_response["header"] != User.banner_url(user)
2394 end
2395
2396 test "requires 'write' permission", %{conn: conn} do
2397 token1 = insert(:oauth_token, scopes: ["read"])
2398 token2 = insert(:oauth_token, scopes: ["write", "follow"])
2399
2400 for token <- [token1, token2] do
2401 conn =
2402 conn
2403 |> put_req_header("authorization", "Bearer #{token.token}")
2404 |> patch("/api/v1/accounts/update_credentials", %{})
2405
2406 if token == token1 do
2407 assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403)
2408 else
2409 assert json_response(conn, 200)
2410 end
2411 end
2412 end
2413
2414 test "updates profile emojos", %{conn: conn} do
2415 user = insert(:user)
2416
2417 note = "*sips :blank:*"
2418 name = "I am :firefox:"
2419
2420 conn =
2421 conn
2422 |> assign(:user, user)
2423 |> patch("/api/v1/accounts/update_credentials", %{
2424 "note" => note,
2425 "display_name" => name
2426 })
2427
2428 assert json_response(conn, 200)
2429
2430 conn =
2431 conn
2432 |> get("/api/v1/accounts/#{user.id}")
2433
2434 assert user = json_response(conn, 200)
2435
2436 assert user["note"] == note
2437 assert user["display_name"] == name
2438 assert [%{"shortcode" => "blank"}, %{"shortcode" => "firefox"}] = user["emojis"]
2439 end
2440 end
2441
2442 test "get instance information", %{conn: conn} do
2443 conn = get(conn, "/api/v1/instance")
2444 assert result = json_response(conn, 200)
2445
2446 email = Pleroma.Config.get([:instance, :email])
2447 # Note: not checking for "max_toot_chars" since it's optional
2448 assert %{
2449 "uri" => _,
2450 "title" => _,
2451 "description" => _,
2452 "version" => _,
2453 "email" => from_config_email,
2454 "urls" => %{
2455 "streaming_api" => _
2456 },
2457 "stats" => _,
2458 "thumbnail" => _,
2459 "languages" => _,
2460 "registrations" => _
2461 } = result
2462
2463 assert email == from_config_email
2464 end
2465
2466 test "get instance stats", %{conn: conn} do
2467 user = insert(:user, %{local: true})
2468
2469 user2 = insert(:user, %{local: true})
2470 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2471
2472 insert(:user, %{local: false, nickname: "u@peer1.com"})
2473 insert(:user, %{local: false, nickname: "u@peer2.com"})
2474
2475 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2476
2477 # Stats should count users with missing or nil `info.deactivated` value
2478 user = User.get_cached_by_id(user.id)
2479 info_change = Changeset.change(user.info, %{deactivated: nil})
2480
2481 {:ok, _user} =
2482 user
2483 |> Changeset.change()
2484 |> Changeset.put_embed(:info, info_change)
2485 |> User.update_and_set_cache()
2486
2487 Pleroma.Stats.update_stats()
2488
2489 conn = get(conn, "/api/v1/instance")
2490
2491 assert result = json_response(conn, 200)
2492
2493 stats = result["stats"]
2494
2495 assert stats
2496 assert stats["user_count"] == 1
2497 assert stats["status_count"] == 1
2498 assert stats["domain_count"] == 2
2499 end
2500
2501 test "get peers", %{conn: conn} do
2502 insert(:user, %{local: false, nickname: "u@peer1.com"})
2503 insert(:user, %{local: false, nickname: "u@peer2.com"})
2504
2505 Pleroma.Stats.update_stats()
2506
2507 conn = get(conn, "/api/v1/instance/peers")
2508
2509 assert result = json_response(conn, 200)
2510
2511 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2512 end
2513
2514 test "put settings", %{conn: conn} do
2515 user = insert(:user)
2516
2517 conn =
2518 conn
2519 |> assign(:user, user)
2520 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2521
2522 assert _result = json_response(conn, 200)
2523
2524 user = User.get_cached_by_ap_id(user.ap_id)
2525 assert user.info.settings == %{"programming" => "socks"}
2526 end
2527
2528 describe "pinned statuses" do
2529 setup do
2530 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2531
2532 user = insert(:user)
2533 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2534
2535 [user: user, activity: activity]
2536 end
2537
2538 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2539 {:ok, _} = CommonAPI.pin(activity.id, user)
2540
2541 result =
2542 conn
2543 |> assign(:user, user)
2544 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2545 |> json_response(200)
2546
2547 id_str = to_string(activity.id)
2548
2549 assert [%{"id" => ^id_str, "pinned" => true}] = result
2550 end
2551
2552 test "pin status", %{conn: conn, user: user, activity: activity} do
2553 id_str = to_string(activity.id)
2554
2555 assert %{"id" => ^id_str, "pinned" => true} =
2556 conn
2557 |> assign(:user, user)
2558 |> post("/api/v1/statuses/#{activity.id}/pin")
2559 |> json_response(200)
2560
2561 assert [%{"id" => ^id_str, "pinned" => true}] =
2562 conn
2563 |> assign(:user, user)
2564 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2565 |> json_response(200)
2566 end
2567
2568 test "unpin status", %{conn: conn, user: user, activity: activity} do
2569 {:ok, _} = CommonAPI.pin(activity.id, user)
2570
2571 id_str = to_string(activity.id)
2572 user = refresh_record(user)
2573
2574 assert %{"id" => ^id_str, "pinned" => false} =
2575 conn
2576 |> assign(:user, user)
2577 |> post("/api/v1/statuses/#{activity.id}/unpin")
2578 |> json_response(200)
2579
2580 assert [] =
2581 conn
2582 |> assign(:user, user)
2583 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2584 |> json_response(200)
2585 end
2586
2587 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2588 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2589
2590 id_str_one = to_string(activity_one.id)
2591
2592 assert %{"id" => ^id_str_one, "pinned" => true} =
2593 conn
2594 |> assign(:user, user)
2595 |> post("/api/v1/statuses/#{id_str_one}/pin")
2596 |> json_response(200)
2597
2598 user = refresh_record(user)
2599
2600 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2601 conn
2602 |> assign(:user, user)
2603 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2604 |> json_response(400)
2605 end
2606
2607 test "Status rich-media Card", %{conn: conn, user: user} do
2608 Pleroma.Config.put([:rich_media, :enabled], true)
2609 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2610
2611 response =
2612 conn
2613 |> get("/api/v1/statuses/#{activity.id}/card")
2614 |> json_response(200)
2615
2616 assert response == %{
2617 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2618 "provider_name" => "www.imdb.com",
2619 "provider_url" => "http://www.imdb.com",
2620 "title" => "The Rock",
2621 "type" => "link",
2622 "url" => "http://www.imdb.com/title/tt0117500/",
2623 "description" => nil,
2624 "pleroma" => %{
2625 "opengraph" => %{
2626 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2627 "title" => "The Rock",
2628 "type" => "video.movie",
2629 "url" => "http://www.imdb.com/title/tt0117500/"
2630 }
2631 }
2632 }
2633
2634 # works with private posts
2635 {:ok, activity} =
2636 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2637
2638 response_two =
2639 conn
2640 |> assign(:user, user)
2641 |> get("/api/v1/statuses/#{activity.id}/card")
2642 |> json_response(200)
2643
2644 assert response_two == response
2645
2646 Pleroma.Config.put([:rich_media, :enabled], false)
2647 end
2648 end
2649
2650 test "bookmarks" do
2651 user = insert(:user)
2652 for_user = insert(:user)
2653
2654 {:ok, activity1} =
2655 CommonAPI.post(user, %{
2656 "status" => "heweoo?"
2657 })
2658
2659 {:ok, activity2} =
2660 CommonAPI.post(user, %{
2661 "status" => "heweoo!"
2662 })
2663
2664 response1 =
2665 build_conn()
2666 |> assign(:user, for_user)
2667 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2668
2669 assert json_response(response1, 200)["bookmarked"] == true
2670
2671 response2 =
2672 build_conn()
2673 |> assign(:user, for_user)
2674 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2675
2676 assert json_response(response2, 200)["bookmarked"] == true
2677
2678 bookmarks =
2679 build_conn()
2680 |> assign(:user, for_user)
2681 |> get("/api/v1/bookmarks")
2682
2683 assert [json_response(response2, 200), json_response(response1, 200)] ==
2684 json_response(bookmarks, 200)
2685
2686 response1 =
2687 build_conn()
2688 |> assign(:user, for_user)
2689 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2690
2691 assert json_response(response1, 200)["bookmarked"] == false
2692
2693 bookmarks =
2694 build_conn()
2695 |> assign(:user, for_user)
2696 |> get("/api/v1/bookmarks")
2697
2698 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2699 end
2700
2701 describe "conversation muting" do
2702 setup do
2703 user = insert(:user)
2704 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2705
2706 [user: user, activity: activity]
2707 end
2708
2709 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2710 id_str = to_string(activity.id)
2711
2712 assert %{"id" => ^id_str, "muted" => true} =
2713 conn
2714 |> assign(:user, user)
2715 |> post("/api/v1/statuses/#{activity.id}/mute")
2716 |> json_response(200)
2717 end
2718
2719 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2720 {:ok, _} = CommonAPI.add_mute(user, activity)
2721
2722 id_str = to_string(activity.id)
2723 user = refresh_record(user)
2724
2725 assert %{"id" => ^id_str, "muted" => false} =
2726 conn
2727 |> assign(:user, user)
2728 |> post("/api/v1/statuses/#{activity.id}/unmute")
2729 |> json_response(200)
2730 end
2731 end
2732
2733 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2734 user = insert(:user)
2735
2736 get_old_flavour =
2737 conn
2738 |> assign(:user, user)
2739 |> get("/api/v1/pleroma/flavour")
2740
2741 assert "glitch" == json_response(get_old_flavour, 200)
2742
2743 set_flavour =
2744 conn
2745 |> assign(:user, user)
2746 |> post("/api/v1/pleroma/flavour/vanilla")
2747
2748 assert "vanilla" == json_response(set_flavour, 200)
2749
2750 get_new_flavour =
2751 conn
2752 |> assign(:user, user)
2753 |> post("/api/v1/pleroma/flavour/vanilla")
2754
2755 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2756 end
2757
2758 describe "reports" do
2759 setup do
2760 reporter = insert(:user)
2761 target_user = insert(:user)
2762
2763 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2764
2765 [reporter: reporter, target_user: target_user, activity: activity]
2766 end
2767
2768 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2769 assert %{"action_taken" => false, "id" => _} =
2770 conn
2771 |> assign(:user, reporter)
2772 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2773 |> json_response(200)
2774 end
2775
2776 test "submit a report with statuses and comment", %{
2777 conn: conn,
2778 reporter: reporter,
2779 target_user: target_user,
2780 activity: activity
2781 } do
2782 assert %{"action_taken" => false, "id" => _} =
2783 conn
2784 |> assign(:user, reporter)
2785 |> post("/api/v1/reports", %{
2786 "account_id" => target_user.id,
2787 "status_ids" => [activity.id],
2788 "comment" => "bad status!"
2789 })
2790 |> json_response(200)
2791 end
2792
2793 test "account_id is required", %{
2794 conn: conn,
2795 reporter: reporter,
2796 activity: activity
2797 } do
2798 assert %{"error" => "Valid `account_id` required"} =
2799 conn
2800 |> assign(:user, reporter)
2801 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2802 |> json_response(400)
2803 end
2804
2805 test "comment must be up to the size specified in the config", %{
2806 conn: conn,
2807 reporter: reporter,
2808 target_user: target_user
2809 } do
2810 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2811 comment = String.pad_trailing("a", max_size + 1, "a")
2812
2813 error = %{"error" => "Comment must be up to #{max_size} characters"}
2814
2815 assert ^error =
2816 conn
2817 |> assign(:user, reporter)
2818 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2819 |> json_response(400)
2820 end
2821 end
2822
2823 describe "link headers" do
2824 test "preserves parameters in link headers", %{conn: conn} do
2825 user = insert(:user)
2826 other_user = insert(:user)
2827
2828 {:ok, activity1} =
2829 CommonAPI.post(other_user, %{
2830 "status" => "hi @#{user.nickname}",
2831 "visibility" => "public"
2832 })
2833
2834 {:ok, activity2} =
2835 CommonAPI.post(other_user, %{
2836 "status" => "hi @#{user.nickname}",
2837 "visibility" => "public"
2838 })
2839
2840 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2841 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2842
2843 conn =
2844 conn
2845 |> assign(:user, user)
2846 |> get("/api/v1/notifications", %{media_only: true})
2847
2848 assert [link_header] = get_resp_header(conn, "link")
2849 assert link_header =~ ~r/media_only=true/
2850 assert link_header =~ ~r/min_id=#{notification2.id}/
2851 assert link_header =~ ~r/max_id=#{notification1.id}/
2852 end
2853 end
2854
2855 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2856 # Need to set an old-style integer ID to reproduce the problem
2857 # (these are no longer assigned to new accounts but were preserved
2858 # for existing accounts during the migration to flakeIDs)
2859 user_one = insert(:user, %{id: 1212})
2860 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2861
2862 resp_one =
2863 conn
2864 |> get("/api/v1/accounts/#{user_one.id}")
2865
2866 resp_two =
2867 conn
2868 |> get("/api/v1/accounts/#{user_two.nickname}")
2869
2870 resp_three =
2871 conn
2872 |> get("/api/v1/accounts/#{user_two.id}")
2873
2874 acc_one = json_response(resp_one, 200)
2875 acc_two = json_response(resp_two, 200)
2876 acc_three = json_response(resp_three, 200)
2877 refute acc_one == acc_two
2878 assert acc_two == acc_three
2879 end
2880
2881 describe "custom emoji" do
2882 test "with tags", %{conn: conn} do
2883 [emoji | _body] =
2884 conn
2885 |> get("/api/v1/custom_emojis")
2886 |> json_response(200)
2887
2888 assert Map.has_key?(emoji, "shortcode")
2889 assert Map.has_key?(emoji, "static_url")
2890 assert Map.has_key?(emoji, "tags")
2891 assert is_list(emoji["tags"])
2892 assert Map.has_key?(emoji, "url")
2893 assert Map.has_key?(emoji, "visible_in_picker")
2894 end
2895 end
2896
2897 describe "index/2 redirections" do
2898 setup %{conn: conn} do
2899 session_opts = [
2900 store: :cookie,
2901 key: "_test",
2902 signing_salt: "cooldude"
2903 ]
2904
2905 conn =
2906 conn
2907 |> Plug.Session.call(Plug.Session.init(session_opts))
2908 |> fetch_session()
2909
2910 test_path = "/web/statuses/test"
2911 %{conn: conn, path: test_path}
2912 end
2913
2914 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2915 conn = get(conn, path)
2916
2917 assert conn.status == 302
2918 assert redirected_to(conn) == "/web/login"
2919 end
2920
2921 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2922 token = insert(:oauth_token)
2923
2924 conn =
2925 conn
2926 |> assign(:user, token.user)
2927 |> put_session(:oauth_token, token.token)
2928 |> get(path)
2929
2930 assert conn.status == 200
2931 end
2932
2933 test "saves referer path to session", %{conn: conn, path: path} do
2934 conn = get(conn, path)
2935 return_to = Plug.Conn.get_session(conn, :return_to)
2936
2937 assert return_to == path
2938 end
2939
2940 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2941 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2942 auth = insert(:oauth_authorization, app: app)
2943
2944 conn =
2945 conn
2946 |> put_session(:return_to, path)
2947 |> get("/web/login", %{code: auth.token})
2948
2949 assert conn.status == 302
2950 assert redirected_to(conn) == path
2951 end
2952
2953 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2954 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2955 auth = insert(:oauth_authorization, app: app)
2956
2957 conn = get(conn, "/web/login", %{code: auth.token})
2958
2959 assert conn.status == 302
2960 assert redirected_to(conn) == "/web/getting-started"
2961 end
2962 end
2963
2964 describe "scheduled activities" do
2965 test "creates a scheduled activity", %{conn: conn} do
2966 user = insert(:user)
2967 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2968
2969 conn =
2970 conn
2971 |> assign(:user, user)
2972 |> post("/api/v1/statuses", %{
2973 "status" => "scheduled",
2974 "scheduled_at" => scheduled_at
2975 })
2976
2977 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2978 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2979 assert [] == Repo.all(Activity)
2980 end
2981
2982 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2983 user = insert(:user)
2984 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2985
2986 file = %Plug.Upload{
2987 content_type: "image/jpg",
2988 path: Path.absname("test/fixtures/image.jpg"),
2989 filename: "an_image.jpg"
2990 }
2991
2992 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2993
2994 conn =
2995 conn
2996 |> assign(:user, user)
2997 |> post("/api/v1/statuses", %{
2998 "media_ids" => [to_string(upload.id)],
2999 "status" => "scheduled",
3000 "scheduled_at" => scheduled_at
3001 })
3002
3003 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
3004 assert %{"type" => "image"} = media_attachment
3005 end
3006
3007 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
3008 %{conn: conn} do
3009 user = insert(:user)
3010
3011 scheduled_at =
3012 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
3013
3014 conn =
3015 conn
3016 |> assign(:user, user)
3017 |> post("/api/v1/statuses", %{
3018 "status" => "not scheduled",
3019 "scheduled_at" => scheduled_at
3020 })
3021
3022 assert %{"content" => "not scheduled"} = json_response(conn, 200)
3023 assert [] == Repo.all(ScheduledActivity)
3024 end
3025
3026 test "returns error when daily user limit is exceeded", %{conn: conn} do
3027 user = insert(:user)
3028
3029 today =
3030 NaiveDateTime.utc_now()
3031 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3032 |> NaiveDateTime.to_iso8601()
3033
3034 attrs = %{params: %{}, scheduled_at: today}
3035 {:ok, _} = ScheduledActivity.create(user, attrs)
3036 {:ok, _} = ScheduledActivity.create(user, attrs)
3037
3038 conn =
3039 conn
3040 |> assign(:user, user)
3041 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3042
3043 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3044 end
3045
3046 test "returns error when total user limit is exceeded", %{conn: conn} do
3047 user = insert(:user)
3048
3049 today =
3050 NaiveDateTime.utc_now()
3051 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3052 |> NaiveDateTime.to_iso8601()
3053
3054 tomorrow =
3055 NaiveDateTime.utc_now()
3056 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3057 |> NaiveDateTime.to_iso8601()
3058
3059 attrs = %{params: %{}, scheduled_at: today}
3060 {:ok, _} = ScheduledActivity.create(user, attrs)
3061 {:ok, _} = ScheduledActivity.create(user, attrs)
3062 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3063
3064 conn =
3065 conn
3066 |> assign(:user, user)
3067 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3068
3069 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3070 end
3071
3072 test "shows scheduled activities", %{conn: conn} do
3073 user = insert(:user)
3074 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3075 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3076 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3077 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3078
3079 conn =
3080 conn
3081 |> assign(:user, user)
3082
3083 # min_id
3084 conn_res =
3085 conn
3086 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3087
3088 result = json_response(conn_res, 200)
3089 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3090
3091 # since_id
3092 conn_res =
3093 conn
3094 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3095
3096 result = json_response(conn_res, 200)
3097 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3098
3099 # max_id
3100 conn_res =
3101 conn
3102 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3103
3104 result = json_response(conn_res, 200)
3105 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3106 end
3107
3108 test "shows a scheduled activity", %{conn: conn} do
3109 user = insert(:user)
3110 scheduled_activity = insert(:scheduled_activity, user: user)
3111
3112 res_conn =
3113 conn
3114 |> assign(:user, user)
3115 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3116
3117 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3118 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3119
3120 res_conn =
3121 conn
3122 |> assign(:user, user)
3123 |> get("/api/v1/scheduled_statuses/404")
3124
3125 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3126 end
3127
3128 test "updates a scheduled activity", %{conn: conn} do
3129 user = insert(:user)
3130 scheduled_activity = insert(:scheduled_activity, user: user)
3131
3132 new_scheduled_at =
3133 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3134
3135 res_conn =
3136 conn
3137 |> assign(:user, user)
3138 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3139 scheduled_at: new_scheduled_at
3140 })
3141
3142 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3143 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3144
3145 res_conn =
3146 conn
3147 |> assign(:user, user)
3148 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3149
3150 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3151 end
3152
3153 test "deletes a scheduled activity", %{conn: conn} do
3154 user = insert(:user)
3155 scheduled_activity = insert(:scheduled_activity, user: user)
3156
3157 res_conn =
3158 conn
3159 |> assign(:user, user)
3160 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3161
3162 assert %{} = json_response(res_conn, 200)
3163 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3164
3165 res_conn =
3166 conn
3167 |> assign(:user, user)
3168 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3169
3170 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3171 end
3172 end
3173
3174 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3175 user1 = insert(:user)
3176 user2 = insert(:user)
3177 user3 = insert(:user)
3178
3179 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
3180
3181 # Reply to status from another user
3182 conn1 =
3183 conn
3184 |> assign(:user, user2)
3185 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3186
3187 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3188
3189 activity = Activity.get_by_id_with_object(id)
3190
3191 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3192 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3193
3194 # Reblog from the third user
3195 conn2 =
3196 conn
3197 |> assign(:user, user3)
3198 |> post("/api/v1/statuses/#{activity.id}/reblog")
3199
3200 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3201 json_response(conn2, 200)
3202
3203 assert to_string(activity.id) == id
3204
3205 # Getting third user status
3206 conn3 =
3207 conn
3208 |> assign(:user, user3)
3209 |> get("api/v1/timelines/home")
3210
3211 [reblogged_activity] = json_response(conn3, 200)
3212
3213 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3214
3215 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3216 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
3217 end
3218 end