Merge remote-tracking branch 'origin/develop' into conversations_three
[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 end
2414
2415 test "get instance information", %{conn: conn} do
2416 conn = get(conn, "/api/v1/instance")
2417 assert result = json_response(conn, 200)
2418
2419 email = Pleroma.Config.get([:instance, :email])
2420 # Note: not checking for "max_toot_chars" since it's optional
2421 assert %{
2422 "uri" => _,
2423 "title" => _,
2424 "description" => _,
2425 "version" => _,
2426 "email" => from_config_email,
2427 "urls" => %{
2428 "streaming_api" => _
2429 },
2430 "stats" => _,
2431 "thumbnail" => _,
2432 "languages" => _,
2433 "registrations" => _
2434 } = result
2435
2436 assert email == from_config_email
2437 end
2438
2439 test "get instance stats", %{conn: conn} do
2440 user = insert(:user, %{local: true})
2441
2442 user2 = insert(:user, %{local: true})
2443 {:ok, _user2} = User.deactivate(user2, !user2.info.deactivated)
2444
2445 insert(:user, %{local: false, nickname: "u@peer1.com"})
2446 insert(:user, %{local: false, nickname: "u@peer2.com"})
2447
2448 {:ok, _} = TwitterAPI.create_status(user, %{"status" => "cofe"})
2449
2450 # Stats should count users with missing or nil `info.deactivated` value
2451 user = User.get_cached_by_id(user.id)
2452 info_change = Changeset.change(user.info, %{deactivated: nil})
2453
2454 {:ok, _user} =
2455 user
2456 |> Changeset.change()
2457 |> Changeset.put_embed(:info, info_change)
2458 |> User.update_and_set_cache()
2459
2460 Pleroma.Stats.update_stats()
2461
2462 conn = get(conn, "/api/v1/instance")
2463
2464 assert result = json_response(conn, 200)
2465
2466 stats = result["stats"]
2467
2468 assert stats
2469 assert stats["user_count"] == 1
2470 assert stats["status_count"] == 1
2471 assert stats["domain_count"] == 2
2472 end
2473
2474 test "get peers", %{conn: conn} do
2475 insert(:user, %{local: false, nickname: "u@peer1.com"})
2476 insert(:user, %{local: false, nickname: "u@peer2.com"})
2477
2478 Pleroma.Stats.update_stats()
2479
2480 conn = get(conn, "/api/v1/instance/peers")
2481
2482 assert result = json_response(conn, 200)
2483
2484 assert ["peer1.com", "peer2.com"] == Enum.sort(result)
2485 end
2486
2487 test "put settings", %{conn: conn} do
2488 user = insert(:user)
2489
2490 conn =
2491 conn
2492 |> assign(:user, user)
2493 |> put("/api/web/settings", %{"data" => %{"programming" => "socks"}})
2494
2495 assert _result = json_response(conn, 200)
2496
2497 user = User.get_cached_by_ap_id(user.ap_id)
2498 assert user.info.settings == %{"programming" => "socks"}
2499 end
2500
2501 describe "pinned statuses" do
2502 setup do
2503 Pleroma.Config.put([:instance, :max_pinned_statuses], 1)
2504
2505 user = insert(:user)
2506 {:ok, activity} = CommonAPI.post(user, %{"status" => "HI!!!"})
2507
2508 [user: user, activity: activity]
2509 end
2510
2511 test "returns pinned statuses", %{conn: conn, user: user, activity: activity} do
2512 {:ok, _} = CommonAPI.pin(activity.id, user)
2513
2514 result =
2515 conn
2516 |> assign(:user, user)
2517 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2518 |> json_response(200)
2519
2520 id_str = to_string(activity.id)
2521
2522 assert [%{"id" => ^id_str, "pinned" => true}] = result
2523 end
2524
2525 test "pin status", %{conn: conn, user: user, activity: activity} do
2526 id_str = to_string(activity.id)
2527
2528 assert %{"id" => ^id_str, "pinned" => true} =
2529 conn
2530 |> assign(:user, user)
2531 |> post("/api/v1/statuses/#{activity.id}/pin")
2532 |> json_response(200)
2533
2534 assert [%{"id" => ^id_str, "pinned" => true}] =
2535 conn
2536 |> assign(:user, user)
2537 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2538 |> json_response(200)
2539 end
2540
2541 test "unpin status", %{conn: conn, user: user, activity: activity} do
2542 {:ok, _} = CommonAPI.pin(activity.id, user)
2543
2544 id_str = to_string(activity.id)
2545 user = refresh_record(user)
2546
2547 assert %{"id" => ^id_str, "pinned" => false} =
2548 conn
2549 |> assign(:user, user)
2550 |> post("/api/v1/statuses/#{activity.id}/unpin")
2551 |> json_response(200)
2552
2553 assert [] =
2554 conn
2555 |> assign(:user, user)
2556 |> get("/api/v1/accounts/#{user.id}/statuses?pinned=true")
2557 |> json_response(200)
2558 end
2559
2560 test "max pinned statuses", %{conn: conn, user: user, activity: activity_one} do
2561 {:ok, activity_two} = CommonAPI.post(user, %{"status" => "HI!!!"})
2562
2563 id_str_one = to_string(activity_one.id)
2564
2565 assert %{"id" => ^id_str_one, "pinned" => true} =
2566 conn
2567 |> assign(:user, user)
2568 |> post("/api/v1/statuses/#{id_str_one}/pin")
2569 |> json_response(200)
2570
2571 user = refresh_record(user)
2572
2573 assert %{"error" => "You have already pinned the maximum number of statuses"} =
2574 conn
2575 |> assign(:user, user)
2576 |> post("/api/v1/statuses/#{activity_two.id}/pin")
2577 |> json_response(400)
2578 end
2579
2580 test "Status rich-media Card", %{conn: conn, user: user} do
2581 Pleroma.Config.put([:rich_media, :enabled], true)
2582 {:ok, activity} = CommonAPI.post(user, %{"status" => "http://example.com/ogp"})
2583
2584 response =
2585 conn
2586 |> get("/api/v1/statuses/#{activity.id}/card")
2587 |> json_response(200)
2588
2589 assert response == %{
2590 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2591 "provider_name" => "www.imdb.com",
2592 "provider_url" => "http://www.imdb.com",
2593 "title" => "The Rock",
2594 "type" => "link",
2595 "url" => "http://www.imdb.com/title/tt0117500/",
2596 "description" => nil,
2597 "pleroma" => %{
2598 "opengraph" => %{
2599 "image" => "http://ia.media-imdb.com/images/rock.jpg",
2600 "title" => "The Rock",
2601 "type" => "video.movie",
2602 "url" => "http://www.imdb.com/title/tt0117500/"
2603 }
2604 }
2605 }
2606
2607 # works with private posts
2608 {:ok, activity} =
2609 CommonAPI.post(user, %{"status" => "http://example.com/ogp", "visibility" => "direct"})
2610
2611 response_two =
2612 conn
2613 |> assign(:user, user)
2614 |> get("/api/v1/statuses/#{activity.id}/card")
2615 |> json_response(200)
2616
2617 assert response_two == response
2618
2619 Pleroma.Config.put([:rich_media, :enabled], false)
2620 end
2621 end
2622
2623 test "bookmarks" do
2624 user = insert(:user)
2625 for_user = insert(:user)
2626
2627 {:ok, activity1} =
2628 CommonAPI.post(user, %{
2629 "status" => "heweoo?"
2630 })
2631
2632 {:ok, activity2} =
2633 CommonAPI.post(user, %{
2634 "status" => "heweoo!"
2635 })
2636
2637 response1 =
2638 build_conn()
2639 |> assign(:user, for_user)
2640 |> post("/api/v1/statuses/#{activity1.id}/bookmark")
2641
2642 assert json_response(response1, 200)["bookmarked"] == true
2643
2644 response2 =
2645 build_conn()
2646 |> assign(:user, for_user)
2647 |> post("/api/v1/statuses/#{activity2.id}/bookmark")
2648
2649 assert json_response(response2, 200)["bookmarked"] == true
2650
2651 bookmarks =
2652 build_conn()
2653 |> assign(:user, for_user)
2654 |> get("/api/v1/bookmarks")
2655
2656 assert [json_response(response2, 200), json_response(response1, 200)] ==
2657 json_response(bookmarks, 200)
2658
2659 response1 =
2660 build_conn()
2661 |> assign(:user, for_user)
2662 |> post("/api/v1/statuses/#{activity1.id}/unbookmark")
2663
2664 assert json_response(response1, 200)["bookmarked"] == false
2665
2666 bookmarks =
2667 build_conn()
2668 |> assign(:user, for_user)
2669 |> get("/api/v1/bookmarks")
2670
2671 assert [json_response(response2, 200)] == json_response(bookmarks, 200)
2672 end
2673
2674 describe "conversation muting" do
2675 setup do
2676 user = insert(:user)
2677 {:ok, activity} = CommonAPI.post(user, %{"status" => "HIE"})
2678
2679 [user: user, activity: activity]
2680 end
2681
2682 test "mute conversation", %{conn: conn, user: user, activity: activity} do
2683 id_str = to_string(activity.id)
2684
2685 assert %{"id" => ^id_str, "muted" => true} =
2686 conn
2687 |> assign(:user, user)
2688 |> post("/api/v1/statuses/#{activity.id}/mute")
2689 |> json_response(200)
2690 end
2691
2692 test "unmute conversation", %{conn: conn, user: user, activity: activity} do
2693 {:ok, _} = CommonAPI.add_mute(user, activity)
2694
2695 id_str = to_string(activity.id)
2696 user = refresh_record(user)
2697
2698 assert %{"id" => ^id_str, "muted" => false} =
2699 conn
2700 |> assign(:user, user)
2701 |> post("/api/v1/statuses/#{activity.id}/unmute")
2702 |> json_response(200)
2703 end
2704 end
2705
2706 test "flavours switching (Pleroma Extension)", %{conn: conn} do
2707 user = insert(:user)
2708
2709 get_old_flavour =
2710 conn
2711 |> assign(:user, user)
2712 |> get("/api/v1/pleroma/flavour")
2713
2714 assert "glitch" == json_response(get_old_flavour, 200)
2715
2716 set_flavour =
2717 conn
2718 |> assign(:user, user)
2719 |> post("/api/v1/pleroma/flavour/vanilla")
2720
2721 assert "vanilla" == json_response(set_flavour, 200)
2722
2723 get_new_flavour =
2724 conn
2725 |> assign(:user, user)
2726 |> post("/api/v1/pleroma/flavour/vanilla")
2727
2728 assert json_response(set_flavour, 200) == json_response(get_new_flavour, 200)
2729 end
2730
2731 describe "reports" do
2732 setup do
2733 reporter = insert(:user)
2734 target_user = insert(:user)
2735
2736 {:ok, activity} = CommonAPI.post(target_user, %{"status" => "foobar"})
2737
2738 [reporter: reporter, target_user: target_user, activity: activity]
2739 end
2740
2741 test "submit a basic report", %{conn: conn, reporter: reporter, target_user: target_user} do
2742 assert %{"action_taken" => false, "id" => _} =
2743 conn
2744 |> assign(:user, reporter)
2745 |> post("/api/v1/reports", %{"account_id" => target_user.id})
2746 |> json_response(200)
2747 end
2748
2749 test "submit a report with statuses and comment", %{
2750 conn: conn,
2751 reporter: reporter,
2752 target_user: target_user,
2753 activity: activity
2754 } do
2755 assert %{"action_taken" => false, "id" => _} =
2756 conn
2757 |> assign(:user, reporter)
2758 |> post("/api/v1/reports", %{
2759 "account_id" => target_user.id,
2760 "status_ids" => [activity.id],
2761 "comment" => "bad status!"
2762 })
2763 |> json_response(200)
2764 end
2765
2766 test "account_id is required", %{
2767 conn: conn,
2768 reporter: reporter,
2769 activity: activity
2770 } do
2771 assert %{"error" => "Valid `account_id` required"} =
2772 conn
2773 |> assign(:user, reporter)
2774 |> post("/api/v1/reports", %{"status_ids" => [activity.id]})
2775 |> json_response(400)
2776 end
2777
2778 test "comment must be up to the size specified in the config", %{
2779 conn: conn,
2780 reporter: reporter,
2781 target_user: target_user
2782 } do
2783 max_size = Pleroma.Config.get([:instance, :max_report_comment_size], 1000)
2784 comment = String.pad_trailing("a", max_size + 1, "a")
2785
2786 error = %{"error" => "Comment must be up to #{max_size} characters"}
2787
2788 assert ^error =
2789 conn
2790 |> assign(:user, reporter)
2791 |> post("/api/v1/reports", %{"account_id" => target_user.id, "comment" => comment})
2792 |> json_response(400)
2793 end
2794 end
2795
2796 describe "link headers" do
2797 test "preserves parameters in link headers", %{conn: conn} do
2798 user = insert(:user)
2799 other_user = insert(:user)
2800
2801 {:ok, activity1} =
2802 CommonAPI.post(other_user, %{
2803 "status" => "hi @#{user.nickname}",
2804 "visibility" => "public"
2805 })
2806
2807 {:ok, activity2} =
2808 CommonAPI.post(other_user, %{
2809 "status" => "hi @#{user.nickname}",
2810 "visibility" => "public"
2811 })
2812
2813 notification1 = Repo.get_by(Notification, activity_id: activity1.id)
2814 notification2 = Repo.get_by(Notification, activity_id: activity2.id)
2815
2816 conn =
2817 conn
2818 |> assign(:user, user)
2819 |> get("/api/v1/notifications", %{media_only: true})
2820
2821 assert [link_header] = get_resp_header(conn, "link")
2822 assert link_header =~ ~r/media_only=true/
2823 assert link_header =~ ~r/min_id=#{notification2.id}/
2824 assert link_header =~ ~r/max_id=#{notification1.id}/
2825 end
2826 end
2827
2828 test "accounts fetches correct account for nicknames beginning with numbers", %{conn: conn} do
2829 # Need to set an old-style integer ID to reproduce the problem
2830 # (these are no longer assigned to new accounts but were preserved
2831 # for existing accounts during the migration to flakeIDs)
2832 user_one = insert(:user, %{id: 1212})
2833 user_two = insert(:user, %{nickname: "#{user_one.id}garbage"})
2834
2835 resp_one =
2836 conn
2837 |> get("/api/v1/accounts/#{user_one.id}")
2838
2839 resp_two =
2840 conn
2841 |> get("/api/v1/accounts/#{user_two.nickname}")
2842
2843 resp_three =
2844 conn
2845 |> get("/api/v1/accounts/#{user_two.id}")
2846
2847 acc_one = json_response(resp_one, 200)
2848 acc_two = json_response(resp_two, 200)
2849 acc_three = json_response(resp_three, 200)
2850 refute acc_one == acc_two
2851 assert acc_two == acc_three
2852 end
2853
2854 describe "custom emoji" do
2855 test "with tags", %{conn: conn} do
2856 [emoji | _body] =
2857 conn
2858 |> get("/api/v1/custom_emojis")
2859 |> json_response(200)
2860
2861 assert Map.has_key?(emoji, "shortcode")
2862 assert Map.has_key?(emoji, "static_url")
2863 assert Map.has_key?(emoji, "tags")
2864 assert is_list(emoji["tags"])
2865 assert Map.has_key?(emoji, "url")
2866 assert Map.has_key?(emoji, "visible_in_picker")
2867 end
2868 end
2869
2870 describe "index/2 redirections" do
2871 setup %{conn: conn} do
2872 session_opts = [
2873 store: :cookie,
2874 key: "_test",
2875 signing_salt: "cooldude"
2876 ]
2877
2878 conn =
2879 conn
2880 |> Plug.Session.call(Plug.Session.init(session_opts))
2881 |> fetch_session()
2882
2883 test_path = "/web/statuses/test"
2884 %{conn: conn, path: test_path}
2885 end
2886
2887 test "redirects not logged-in users to the login page", %{conn: conn, path: path} do
2888 conn = get(conn, path)
2889
2890 assert conn.status == 302
2891 assert redirected_to(conn) == "/web/login"
2892 end
2893
2894 test "does not redirect logged in users to the login page", %{conn: conn, path: path} do
2895 token = insert(:oauth_token)
2896
2897 conn =
2898 conn
2899 |> assign(:user, token.user)
2900 |> put_session(:oauth_token, token.token)
2901 |> get(path)
2902
2903 assert conn.status == 200
2904 end
2905
2906 test "saves referer path to session", %{conn: conn, path: path} do
2907 conn = get(conn, path)
2908 return_to = Plug.Conn.get_session(conn, :return_to)
2909
2910 assert return_to == path
2911 end
2912
2913 test "redirects to the saved path after log in", %{conn: conn, path: path} do
2914 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2915 auth = insert(:oauth_authorization, app: app)
2916
2917 conn =
2918 conn
2919 |> put_session(:return_to, path)
2920 |> get("/web/login", %{code: auth.token})
2921
2922 assert conn.status == 302
2923 assert redirected_to(conn) == path
2924 end
2925
2926 test "redirects to the getting-started page when referer is not present", %{conn: conn} do
2927 app = insert(:oauth_app, client_name: "Mastodon-Local", redirect_uris: ".")
2928 auth = insert(:oauth_authorization, app: app)
2929
2930 conn = get(conn, "/web/login", %{code: auth.token})
2931
2932 assert conn.status == 302
2933 assert redirected_to(conn) == "/web/getting-started"
2934 end
2935 end
2936
2937 describe "scheduled activities" do
2938 test "creates a scheduled activity", %{conn: conn} do
2939 user = insert(:user)
2940 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2941
2942 conn =
2943 conn
2944 |> assign(:user, user)
2945 |> post("/api/v1/statuses", %{
2946 "status" => "scheduled",
2947 "scheduled_at" => scheduled_at
2948 })
2949
2950 assert %{"scheduled_at" => expected_scheduled_at} = json_response(conn, 200)
2951 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(scheduled_at)
2952 assert [] == Repo.all(Activity)
2953 end
2954
2955 test "creates a scheduled activity with a media attachment", %{conn: conn} do
2956 user = insert(:user)
2957 scheduled_at = NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
2958
2959 file = %Plug.Upload{
2960 content_type: "image/jpg",
2961 path: Path.absname("test/fixtures/image.jpg"),
2962 filename: "an_image.jpg"
2963 }
2964
2965 {:ok, upload} = ActivityPub.upload(file, actor: user.ap_id)
2966
2967 conn =
2968 conn
2969 |> assign(:user, user)
2970 |> post("/api/v1/statuses", %{
2971 "media_ids" => [to_string(upload.id)],
2972 "status" => "scheduled",
2973 "scheduled_at" => scheduled_at
2974 })
2975
2976 assert %{"media_attachments" => [media_attachment]} = json_response(conn, 200)
2977 assert %{"type" => "image"} = media_attachment
2978 end
2979
2980 test "skips the scheduling and creates the activity if scheduled_at is earlier than 5 minutes from now",
2981 %{conn: conn} do
2982 user = insert(:user)
2983
2984 scheduled_at =
2985 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(5) - 1, :millisecond)
2986
2987 conn =
2988 conn
2989 |> assign(:user, user)
2990 |> post("/api/v1/statuses", %{
2991 "status" => "not scheduled",
2992 "scheduled_at" => scheduled_at
2993 })
2994
2995 assert %{"content" => "not scheduled"} = json_response(conn, 200)
2996 assert [] == Repo.all(ScheduledActivity)
2997 end
2998
2999 test "returns error when daily user limit is exceeded", %{conn: conn} do
3000 user = insert(:user)
3001
3002 today =
3003 NaiveDateTime.utc_now()
3004 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3005 |> NaiveDateTime.to_iso8601()
3006
3007 attrs = %{params: %{}, scheduled_at: today}
3008 {:ok, _} = ScheduledActivity.create(user, attrs)
3009 {:ok, _} = ScheduledActivity.create(user, attrs)
3010
3011 conn =
3012 conn
3013 |> assign(:user, user)
3014 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => today})
3015
3016 assert %{"error" => "daily limit exceeded"} == json_response(conn, 422)
3017 end
3018
3019 test "returns error when total user limit is exceeded", %{conn: conn} do
3020 user = insert(:user)
3021
3022 today =
3023 NaiveDateTime.utc_now()
3024 |> NaiveDateTime.add(:timer.minutes(6), :millisecond)
3025 |> NaiveDateTime.to_iso8601()
3026
3027 tomorrow =
3028 NaiveDateTime.utc_now()
3029 |> NaiveDateTime.add(:timer.hours(36), :millisecond)
3030 |> NaiveDateTime.to_iso8601()
3031
3032 attrs = %{params: %{}, scheduled_at: today}
3033 {:ok, _} = ScheduledActivity.create(user, attrs)
3034 {:ok, _} = ScheduledActivity.create(user, attrs)
3035 {:ok, _} = ScheduledActivity.create(user, %{params: %{}, scheduled_at: tomorrow})
3036
3037 conn =
3038 conn
3039 |> assign(:user, user)
3040 |> post("/api/v1/statuses", %{"status" => "scheduled", "scheduled_at" => tomorrow})
3041
3042 assert %{"error" => "total limit exceeded"} == json_response(conn, 422)
3043 end
3044
3045 test "shows scheduled activities", %{conn: conn} do
3046 user = insert(:user)
3047 scheduled_activity_id1 = insert(:scheduled_activity, user: user).id |> to_string()
3048 scheduled_activity_id2 = insert(:scheduled_activity, user: user).id |> to_string()
3049 scheduled_activity_id3 = insert(:scheduled_activity, user: user).id |> to_string()
3050 scheduled_activity_id4 = insert(:scheduled_activity, user: user).id |> to_string()
3051
3052 conn =
3053 conn
3054 |> assign(:user, user)
3055
3056 # min_id
3057 conn_res =
3058 conn
3059 |> get("/api/v1/scheduled_statuses?limit=2&min_id=#{scheduled_activity_id1}")
3060
3061 result = json_response(conn_res, 200)
3062 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3063
3064 # since_id
3065 conn_res =
3066 conn
3067 |> get("/api/v1/scheduled_statuses?limit=2&since_id=#{scheduled_activity_id1}")
3068
3069 result = json_response(conn_res, 200)
3070 assert [%{"id" => ^scheduled_activity_id4}, %{"id" => ^scheduled_activity_id3}] = result
3071
3072 # max_id
3073 conn_res =
3074 conn
3075 |> get("/api/v1/scheduled_statuses?limit=2&max_id=#{scheduled_activity_id4}")
3076
3077 result = json_response(conn_res, 200)
3078 assert [%{"id" => ^scheduled_activity_id3}, %{"id" => ^scheduled_activity_id2}] = result
3079 end
3080
3081 test "shows a scheduled activity", %{conn: conn} do
3082 user = insert(:user)
3083 scheduled_activity = insert(:scheduled_activity, user: user)
3084
3085 res_conn =
3086 conn
3087 |> assign(:user, user)
3088 |> get("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3089
3090 assert %{"id" => scheduled_activity_id} = json_response(res_conn, 200)
3091 assert scheduled_activity_id == scheduled_activity.id |> to_string()
3092
3093 res_conn =
3094 conn
3095 |> assign(:user, user)
3096 |> get("/api/v1/scheduled_statuses/404")
3097
3098 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3099 end
3100
3101 test "updates a scheduled activity", %{conn: conn} do
3102 user = insert(:user)
3103 scheduled_activity = insert(:scheduled_activity, user: user)
3104
3105 new_scheduled_at =
3106 NaiveDateTime.add(NaiveDateTime.utc_now(), :timer.minutes(120), :millisecond)
3107
3108 res_conn =
3109 conn
3110 |> assign(:user, user)
3111 |> put("/api/v1/scheduled_statuses/#{scheduled_activity.id}", %{
3112 scheduled_at: new_scheduled_at
3113 })
3114
3115 assert %{"scheduled_at" => expected_scheduled_at} = json_response(res_conn, 200)
3116 assert expected_scheduled_at == Pleroma.Web.CommonAPI.Utils.to_masto_date(new_scheduled_at)
3117
3118 res_conn =
3119 conn
3120 |> assign(:user, user)
3121 |> put("/api/v1/scheduled_statuses/404", %{scheduled_at: new_scheduled_at})
3122
3123 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3124 end
3125
3126 test "deletes a scheduled activity", %{conn: conn} do
3127 user = insert(:user)
3128 scheduled_activity = insert(:scheduled_activity, user: user)
3129
3130 res_conn =
3131 conn
3132 |> assign(:user, user)
3133 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3134
3135 assert %{} = json_response(res_conn, 200)
3136 assert nil == Repo.get(ScheduledActivity, scheduled_activity.id)
3137
3138 res_conn =
3139 conn
3140 |> assign(:user, user)
3141 |> delete("/api/v1/scheduled_statuses/#{scheduled_activity.id}")
3142
3143 assert %{"error" => "Record not found"} = json_response(res_conn, 404)
3144 end
3145 end
3146
3147 test "Repeated posts that are replies incorrectly have in_reply_to_id null", %{conn: conn} do
3148 user1 = insert(:user)
3149 user2 = insert(:user)
3150 user3 = insert(:user)
3151
3152 {:ok, replied_to} = TwitterAPI.create_status(user1, %{"status" => "cofe"})
3153
3154 # Reply to status from another user
3155 conn1 =
3156 conn
3157 |> assign(:user, user2)
3158 |> post("/api/v1/statuses", %{"status" => "xD", "in_reply_to_id" => replied_to.id})
3159
3160 assert %{"content" => "xD", "id" => id} = json_response(conn1, 200)
3161
3162 activity = Activity.get_by_id_with_object(id)
3163
3164 assert Object.normalize(activity).data["inReplyTo"] == Object.normalize(replied_to).data["id"]
3165 assert Activity.get_in_reply_to_activity(activity).id == replied_to.id
3166
3167 # Reblog from the third user
3168 conn2 =
3169 conn
3170 |> assign(:user, user3)
3171 |> post("/api/v1/statuses/#{activity.id}/reblog")
3172
3173 assert %{"reblog" => %{"id" => id, "reblogged" => true, "reblogs_count" => 1}} =
3174 json_response(conn2, 200)
3175
3176 assert to_string(activity.id) == id
3177
3178 # Getting third user status
3179 conn3 =
3180 conn
3181 |> assign(:user, user3)
3182 |> get("api/v1/timelines/home")
3183
3184 [reblogged_activity] = json_response(conn3, 200)
3185
3186 assert reblogged_activity["reblog"]["in_reply_to_id"] == replied_to.id
3187
3188 replied_to_user = User.get_by_ap_id(replied_to.data["actor"])
3189 assert reblogged_activity["reblog"]["in_reply_to_account_id"] == replied_to_user.id
3190 end
3191 end