1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
6 use Pleroma.Web.ConnCase
12 alias Pleroma.Web.CommonAPI
15 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
20 setup do: oauth_access(["read:statuses"])
22 test "does NOT embed account/pleroma/relationship in statuses", %{
26 other_user = insert(:user)
28 {:ok, _} = CommonAPI.post(other_user, %{status: "hi @#{user.nickname}"})
32 |> assign(:user, user)
33 |> get("/api/v1/timelines/home")
34 |> json_response_and_validate_schema(200)
36 assert Enum.all?(response, fn n ->
37 get_in(n, ["account", "pleroma", "relationship"]) == %{}
41 test "the home timeline when the direct messages are excluded", %{user: user, conn: conn} do
42 {:ok, public_activity} = CommonAPI.post(user, %{status: ".", visibility: "public"})
43 {:ok, direct_activity} = CommonAPI.post(user, %{status: ".", visibility: "direct"})
45 {:ok, unlisted_activity} = CommonAPI.post(user, %{status: ".", visibility: "unlisted"})
47 {:ok, private_activity} = CommonAPI.post(user, %{status: ".", visibility: "private"})
49 conn = get(conn, "/api/v1/timelines/home?exclude_visibilities[]=direct")
51 assert status_ids = json_response_and_validate_schema(conn, :ok) |> Enum.map(& &1["id"])
52 assert public_activity.id in status_ids
53 assert unlisted_activity.id in status_ids
54 assert private_activity.id in status_ids
55 refute direct_activity.id in status_ids
58 test "muted emotions", %{user: user, conn: conn} do
59 other_user = insert(:user)
60 {:ok, activity} = CommonAPI.post(user, %{status: "."})
62 {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
63 User.mute(user, other_user)
67 |> assign(:user, user)
68 |> get("/api/v1/timelines/home")
69 |> json_response_and_validate_schema(200)
74 "emoji_reactions" => []
81 |> assign(:user, user)
82 |> get("/api/v1/timelines/home?with_muted=true")
83 |> json_response_and_validate_schema(200)
88 "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
94 test "local/remote filtering", %{conn: conn, user: user} do
95 local_user = insert(:user)
96 {:ok, user, local_user} = User.follow(user, local_user)
97 {:ok, local_activity} = CommonAPI.post(local_user, %{status: "Status"})
99 remote_user = insert(:user, local: false)
100 {:ok, _user, remote_user} = User.follow(user, remote_user)
101 remote_activity = create_remote_activity(remote_user)
105 |> get("/api/v1/timelines/home")
106 |> json_response_and_validate_schema(200)
108 without_filter_ids = Enum.map(resp1, & &1["id"])
110 assert local_activity.id in without_filter_ids
111 assert remote_activity.id in without_filter_ids
115 |> get("/api/v1/timelines/home?local=true")
116 |> json_response_and_validate_schema(200)
118 only_local_ids = Enum.map(resp2, & &1["id"])
120 assert local_activity.id in only_local_ids
121 refute remote_activity.id in only_local_ids
125 |> get("/api/v1/timelines/home?only_remote=true")
126 |> json_response_and_validate_schema(200)
128 only_remote_ids = Enum.map(resp3, & &1["id"])
130 refute local_activity.id in only_remote_ids
131 assert remote_activity.id in only_remote_ids
135 |> get("/api/v1/timelines/home?only_remote=true&local=true")
136 |> json_response_and_validate_schema(200)
141 test "only_media flag", %{conn: conn, user: user} do
142 other = insert(:user)
143 {:ok, _, other} = User.follow(user, other)
145 {:ok, without_media} = CommonAPI.post(other, %{status: "some status"})
147 with_media = create_with_media_activity(other)
151 |> get("/api/v1/timelines/home")
152 |> json_response_and_validate_schema(200)
154 without_filter_ids = Enum.map(resp1, & &1["id"])
156 assert without_media.id in without_filter_ids
157 assert with_media.id in without_filter_ids
161 |> get("/api/v1/timelines/home?only_media=true")
162 |> json_response_and_validate_schema(200)
164 only_media_ids = Enum.map(resp2, & &1["id"])
166 refute without_media.id in only_media_ids
167 assert with_media.id in only_media_ids
172 @tag capture_log: true
173 test "the public timeline", %{conn: conn} do
176 {:ok, activity} = CommonAPI.post(user, %{status: "test"})
178 _activity = insert(:note_activity, local: false)
180 conn = get(conn, "/api/v1/timelines/public?local=False")
182 assert length(json_response_and_validate_schema(conn, :ok)) == 2
184 conn = get(build_conn(), "/api/v1/timelines/public?local=True")
186 assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok)
188 conn = get(build_conn(), "/api/v1/timelines/public?local=1")
190 assert [%{"content" => "test"}] = json_response_and_validate_schema(conn, :ok)
192 # does not contain repeats
193 {:ok, _} = CommonAPI.repeat(activity.id, user)
195 conn = get(build_conn(), "/api/v1/timelines/public?local=true")
197 assert [_] = json_response_and_validate_schema(conn, :ok)
200 test "the public timeline includes only public statuses for an authenticated user" do
201 %{user: user, conn: conn} = oauth_access(["read:statuses"])
203 {:ok, _activity} = CommonAPI.post(user, %{status: "test"})
204 {:ok, _activity} = CommonAPI.post(user, %{status: "test", visibility: "private"})
205 {:ok, _activity} = CommonAPI.post(user, %{status: "test", visibility: "unlisted"})
206 {:ok, _activity} = CommonAPI.post(user, %{status: "test", visibility: "direct"})
208 res_conn = get(conn, "/api/v1/timelines/public")
209 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
212 test "doesn't return replies if follower is posting with blocked user" do
213 %{conn: conn, user: blocker} = oauth_access(["read:statuses"])
214 [blockee, friend] = insert_list(2, :user)
215 {:ok, blocker, friend} = User.follow(blocker, friend)
216 {:ok, _} = User.block(blocker, blockee)
218 conn = assign(conn, :user, blocker)
220 {:ok, %{id: activity_id} = activity} = CommonAPI.post(friend, %{status: "hey!"})
222 {:ok, reply_from_blockee} =
223 CommonAPI.post(blockee, %{status: "heya", in_reply_to_status_id: activity})
225 {:ok, _reply_from_friend} =
226 CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee})
228 # Still shows replies from yourself
229 {:ok, %{id: reply_from_me}} =
230 CommonAPI.post(blocker, %{status: "status", in_reply_to_status_id: reply_from_blockee})
233 get(conn, "/api/v1/timelines/public")
234 |> json_response_and_validate_schema(200)
236 assert length(response) == 2
237 [%{"id" => ^reply_from_me}, %{"id" => ^activity_id}] = response
240 test "doesn't return replies if follow is posting with users from blocked domain" do
241 %{conn: conn, user: blocker} = oauth_access(["read:statuses"])
242 friend = insert(:user)
243 blockee = insert(:user, ap_id: "https://example.com/users/blocked")
244 {:ok, blocker, friend} = User.follow(blocker, friend)
245 {:ok, blocker} = User.block_domain(blocker, "example.com")
247 conn = assign(conn, :user, blocker)
249 {:ok, %{id: activity_id} = activity} = CommonAPI.post(friend, %{status: "hey!"})
251 {:ok, reply_from_blockee} =
252 CommonAPI.post(blockee, %{status: "heya", in_reply_to_status_id: activity})
254 {:ok, _reply_from_friend} =
255 CommonAPI.post(friend, %{status: "status", in_reply_to_status_id: reply_from_blockee})
257 res_conn = get(conn, "/api/v1/timelines/public")
259 activities = json_response_and_validate_schema(res_conn, 200)
260 [%{"id" => ^activity_id}] = activities
263 test "can be filtered by instance", %{conn: conn} do
264 user = insert(:user, ap_id: "https://lain.com/users/lain")
265 insert(:note_activity, local: false)
266 insert(:note_activity, local: false)
268 {:ok, _} = CommonAPI.post(user, %{status: "test"})
270 conn = get(conn, "/api/v1/timelines/public?instance=lain.com")
272 assert length(json_response_and_validate_schema(conn, :ok)) == 1
275 test "muted emotions", %{conn: conn} do
277 token = insert(:oauth_token, user: user, scopes: ["read:statuses"])
281 |> assign(:user, user)
282 |> assign(:token, token)
284 other_user = insert(:user)
285 {:ok, activity} = CommonAPI.post(user, %{status: "."})
287 {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
288 User.mute(user, other_user)
292 |> get("/api/v1/timelines/public")
293 |> json_response_and_validate_schema(200)
298 "emoji_reactions" => []
305 |> get("/api/v1/timelines/public?with_muted=true")
306 |> json_response_and_validate_schema(200)
311 "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
318 defp local_and_remote_activities do
319 insert(:note_activity)
320 insert(:note_activity, local: false)
324 describe "public with restrict unauthenticated timeline for local and federated timelines" do
325 setup do: local_and_remote_activities()
327 setup do: clear_config([:restrict_unauthenticated, :timelines, :local], true)
329 setup do: clear_config([:restrict_unauthenticated, :timelines, :federated], true)
331 test "if user is unauthenticated", %{conn: conn} do
332 res_conn = get(conn, "/api/v1/timelines/public?local=true")
334 assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
335 "error" => "authorization required for timeline view"
338 res_conn = get(conn, "/api/v1/timelines/public?local=false")
340 assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
341 "error" => "authorization required for timeline view"
345 test "if user is authenticated" do
346 %{conn: conn} = oauth_access(["read:statuses"])
348 res_conn = get(conn, "/api/v1/timelines/public?local=true")
349 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
351 res_conn = get(conn, "/api/v1/timelines/public?local=false")
352 assert length(json_response_and_validate_schema(res_conn, 200)) == 2
356 describe "public with restrict unauthenticated timeline for local" do
357 setup do: local_and_remote_activities()
359 setup do: clear_config([:restrict_unauthenticated, :timelines, :local], true)
361 test "if user is unauthenticated", %{conn: conn} do
362 res_conn = get(conn, "/api/v1/timelines/public?local=true")
364 assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
365 "error" => "authorization required for timeline view"
368 res_conn = get(conn, "/api/v1/timelines/public?local=false")
369 assert length(json_response_and_validate_schema(res_conn, 200)) == 2
372 test "if user is authenticated", %{conn: _conn} do
373 %{conn: conn} = oauth_access(["read:statuses"])
375 res_conn = get(conn, "/api/v1/timelines/public?local=true")
376 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
378 res_conn = get(conn, "/api/v1/timelines/public?local=false")
379 assert length(json_response_and_validate_schema(res_conn, 200)) == 2
383 describe "public with restrict unauthenticated timeline for remote" do
384 setup do: local_and_remote_activities()
386 setup do: clear_config([:restrict_unauthenticated, :timelines, :federated], true)
388 test "if user is unauthenticated", %{conn: conn} do
389 res_conn = get(conn, "/api/v1/timelines/public?local=true")
390 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
392 res_conn = get(conn, "/api/v1/timelines/public?local=false")
394 assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
395 "error" => "authorization required for timeline view"
399 test "if user is authenticated", %{conn: _conn} do
400 %{conn: conn} = oauth_access(["read:statuses"])
402 res_conn = get(conn, "/api/v1/timelines/public?local=true")
403 assert length(json_response_and_validate_schema(res_conn, 200)) == 1
405 res_conn = get(conn, "/api/v1/timelines/public?local=false")
406 assert length(json_response_and_validate_schema(res_conn, 200)) == 2
411 test "direct timeline", %{conn: conn} do
412 user_one = insert(:user)
413 user_two = insert(:user)
415 {:ok, user_two, user_one} = User.follow(user_two, user_one)
418 CommonAPI.post(user_one, %{
419 status: "Hi @#{user_two.nickname}!",
423 {:ok, _follower_only} =
424 CommonAPI.post(user_one, %{
425 status: "Hi @#{user_two.nickname}!",
426 visibility: "private"
431 |> assign(:user, user_two)
432 |> assign(:token, insert(:oauth_token, user: user_two, scopes: ["read:statuses"]))
434 # Only direct should be visible here
435 res_conn = get(conn_user_two, "api/v1/timelines/direct")
437 assert [status] = json_response_and_validate_schema(res_conn, :ok)
439 assert %{"visibility" => "direct"} = status
440 assert status["url"] != direct.data["id"]
442 # User should be able to see their own direct message
445 |> assign(:user, user_one)
446 |> assign(:token, insert(:oauth_token, user: user_one, scopes: ["read:statuses"]))
447 |> get("api/v1/timelines/direct")
449 [status] = json_response_and_validate_schema(res_conn, :ok)
451 assert %{"visibility" => "direct"} = status
453 # Both should be visible here
454 res_conn = get(conn_user_two, "api/v1/timelines/home")
456 [_s1, _s2] = json_response_and_validate_schema(res_conn, :ok)
459 Enum.each(1..20, fn _ ->
461 CommonAPI.post(user_one, %{
462 status: "Hi @#{user_two.nickname}!",
467 res_conn = get(conn_user_two, "api/v1/timelines/direct")
469 statuses = json_response_and_validate_schema(res_conn, :ok)
470 assert length(statuses) == 20
472 max_id = List.last(statuses)["id"]
474 res_conn = get(conn_user_two, "api/v1/timelines/direct?max_id=#{max_id}")
476 assert [status] = json_response_and_validate_schema(res_conn, :ok)
478 assert status["url"] != direct.data["id"]
481 test "doesn't include DMs from blocked users" do
482 %{user: blocker, conn: conn} = oauth_access(["read:statuses"])
483 blocked = insert(:user)
484 other_user = insert(:user)
485 {:ok, _user_relationship} = User.block(blocker, blocked)
487 {:ok, _blocked_direct} =
488 CommonAPI.post(blocked, %{
489 status: "Hi @#{blocker.nickname}!",
494 CommonAPI.post(other_user, %{
495 status: "Hi @#{blocker.nickname}!",
499 res_conn = get(conn, "api/v1/timelines/direct")
501 [status] = json_response_and_validate_schema(res_conn, :ok)
502 assert status["id"] == direct.id
507 setup do: oauth_access(["read:lists"])
509 test "does not contain retoots", %{user: user, conn: conn} do
510 other_user = insert(:user)
511 {:ok, activity_one} = CommonAPI.post(user, %{status: "Marisa is cute."})
512 {:ok, activity_two} = CommonAPI.post(other_user, %{status: "Marisa is stupid."})
513 {:ok, _} = CommonAPI.repeat(activity_one.id, other_user)
515 {:ok, list} = Pleroma.List.create("name", user)
516 {:ok, list} = Pleroma.List.follow(list, other_user)
518 conn = get(conn, "/api/v1/timelines/list/#{list.id}")
520 assert [%{"id" => id}] = json_response_and_validate_schema(conn, :ok)
522 assert id == to_string(activity_two.id)
525 test "works with pagination", %{user: user, conn: conn} do
526 other_user = insert(:user)
527 {:ok, list} = Pleroma.List.create("name", user)
528 {:ok, list} = Pleroma.List.follow(list, other_user)
530 Enum.each(1..30, fn i ->
531 CommonAPI.post(other_user, %{status: "post number #{i}"})
535 get(conn, "/api/v1/timelines/list/#{list.id}?limit=1")
536 |> json_response_and_validate_schema(:ok)
538 assert length(res) == 1
543 get(conn, "/api/v1/timelines/list/#{list.id}?max_id=#{first["id"]}&limit=30")
544 |> json_response_and_validate_schema(:ok)
546 assert length(res) == 29
549 test "list timeline", %{user: user, conn: conn} do
550 other_user = insert(:user)
551 {:ok, _activity_one} = CommonAPI.post(user, %{status: "Marisa is cute."})
552 {:ok, activity_two} = CommonAPI.post(other_user, %{status: "Marisa is cute."})
553 {:ok, list} = Pleroma.List.create("name", user)
554 {:ok, list} = Pleroma.List.follow(list, other_user)
556 conn = get(conn, "/api/v1/timelines/list/#{list.id}")
558 assert [%{"id" => id}] = json_response_and_validate_schema(conn, :ok)
560 assert id == to_string(activity_two.id)
563 test "list timeline does not leak non-public statuses for unfollowed users", %{
567 other_user = insert(:user)
568 {:ok, activity_one} = CommonAPI.post(other_user, %{status: "Marisa is cute."})
570 {:ok, _activity_two} =
571 CommonAPI.post(other_user, %{
572 status: "Marisa is cute.",
573 visibility: "private"
576 {:ok, list} = Pleroma.List.create("name", user)
577 {:ok, list} = Pleroma.List.follow(list, other_user)
579 conn = get(conn, "/api/v1/timelines/list/#{list.id}")
581 assert [%{"id" => id}] = json_response_and_validate_schema(conn, :ok)
583 assert id == to_string(activity_one.id)
586 test "muted emotions", %{user: user, conn: conn} do
587 user2 = insert(:user)
588 user3 = insert(:user)
589 {:ok, activity} = CommonAPI.post(user2, %{status: "."})
591 {:ok, _} = CommonAPI.react_with_emoji(activity.id, user3, "🎅")
592 User.mute(user, user3)
594 {:ok, list} = Pleroma.List.create("name", user)
595 {:ok, list} = Pleroma.List.follow(list, user2)
599 |> get("/api/v1/timelines/list/#{list.id}")
600 |> json_response_and_validate_schema(200)
605 "emoji_reactions" => []
612 |> get("/api/v1/timelines/list/#{list.id}?with_muted=true")
613 |> json_response_and_validate_schema(200)
618 "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
624 test "filering with params", %{user: user, conn: conn} do
625 {:ok, list} = Pleroma.List.create("name", user)
627 local_user = insert(:user)
628 {:ok, local_activity} = CommonAPI.post(local_user, %{status: "Marisa is stupid."})
629 with_media = create_with_media_activity(local_user)
630 {:ok, list} = Pleroma.List.follow(list, local_user)
632 remote_user = insert(:user, local: false)
633 remote_activity = create_remote_activity(remote_user)
634 {:ok, list} = Pleroma.List.follow(list, remote_user)
637 conn |> get("/api/v1/timelines/list/#{list.id}") |> json_response_and_validate_schema(200)
639 all_ids = Enum.map(resp1, & &1["id"])
641 assert local_activity.id in all_ids
642 assert with_media.id in all_ids
643 assert remote_activity.id in all_ids
647 |> get("/api/v1/timelines/list/#{list.id}?local=true")
648 |> json_response_and_validate_schema(200)
650 only_local_ids = Enum.map(resp2, & &1["id"])
652 assert local_activity.id in only_local_ids
653 assert with_media.id in only_local_ids
654 refute remote_activity.id in only_local_ids
658 |> get("/api/v1/timelines/list/#{list.id}?only_remote=true")
659 |> json_response_and_validate_schema(200)
661 only_remote_ids = Enum.map(resp3, & &1["id"])
663 refute local_activity.id in only_remote_ids
664 refute with_media.id in only_remote_ids
665 assert remote_activity.id in only_remote_ids
669 |> get("/api/v1/timelines/list/#{list.id}?only_media=true")
670 |> json_response_and_validate_schema(200)
672 only_media_ids = Enum.map(resp4, & &1["id"])
674 refute local_activity.id in only_media_ids
675 assert with_media.id in only_media_ids
676 refute remote_activity.id in only_media_ids
680 "/api/v1/timelines/list/#{list.id}?only_media=true&local=true&only_remote=true"
682 |> json_response_and_validate_schema(200) == []
686 describe "hashtag" do
687 setup do: oauth_access(["n/a"])
689 @tag capture_log: true
690 test "hashtag timeline", %{conn: conn} do
691 following = insert(:user)
693 {:ok, activity} = CommonAPI.post(following, %{status: "test #2hu"})
695 nconn = get(conn, "/api/v1/timelines/tag/2hu")
697 assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok)
699 assert id == to_string(activity.id)
701 # works for different capitalization too
702 nconn = get(conn, "/api/v1/timelines/tag/2HU")
704 assert [%{"id" => id}] = json_response_and_validate_schema(nconn, :ok)
706 assert id == to_string(activity.id)
709 test "multi-hashtag timeline", %{conn: conn} do
712 {:ok, activity_test} = CommonAPI.post(user, %{status: "#test"})
713 {:ok, activity_test1} = CommonAPI.post(user, %{status: "#test #test1"})
714 {:ok, activity_none} = CommonAPI.post(user, %{status: "#test #none"})
716 any_test = get(conn, "/api/v1/timelines/tag/test?any[]=test1")
718 [status_none, status_test1, status_test] = json_response_and_validate_schema(any_test, :ok)
720 assert to_string(activity_test.id) == status_test["id"]
721 assert to_string(activity_test1.id) == status_test1["id"]
722 assert to_string(activity_none.id) == status_none["id"]
724 restricted_test = get(conn, "/api/v1/timelines/tag/test?all[]=test1&none[]=none")
726 assert [status_test1] == json_response_and_validate_schema(restricted_test, :ok)
728 all_test = get(conn, "/api/v1/timelines/tag/test?all[]=none")
730 assert [status_none] == json_response_and_validate_schema(all_test, :ok)
733 test "muted emotions", %{conn: conn} do
735 token = insert(:oauth_token, user: user, scopes: ["read:statuses"])
739 |> assign(:user, user)
740 |> assign(:token, token)
742 other_user = insert(:user)
743 {:ok, activity} = CommonAPI.post(user, %{status: "test #2hu"})
745 {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
746 User.mute(user, other_user)
750 |> get("/api/v1/timelines/tag/2hu")
751 |> json_response_and_validate_schema(200)
756 "emoji_reactions" => []
763 |> get("/api/v1/timelines/tag/2hu?with_muted=true")
764 |> json_response_and_validate_schema(200)
769 "emoji_reactions" => [%{"count" => 1, "me" => false, "name" => "🎅"}]
776 describe "hashtag timeline handling of :restrict_unauthenticated setting" do
779 {:ok, activity1} = CommonAPI.post(user, %{status: "test #tag1"})
780 {:ok, _activity2} = CommonAPI.post(user, %{status: "test #tag1"})
783 |> Ecto.Changeset.change(%{local: false})
784 |> Pleroma.Repo.update()
786 base_uri = "/api/v1/timelines/tag/tag1"
787 error_response = %{"error" => "authorization required for timeline view"}
789 %{base_uri: base_uri, error_response: error_response}
792 defp ensure_authenticated_access(base_uri) do
793 %{conn: auth_conn} = oauth_access(["read:statuses"])
795 res_conn = get(auth_conn, "#{base_uri}?local=true")
796 assert length(json_response(res_conn, 200)) == 1
798 res_conn = get(auth_conn, "#{base_uri}?local=false")
799 assert length(json_response(res_conn, 200)) == 2
802 test "with default settings on private instances, returns 403 for unauthenticated users", %{
805 error_response: error_response
807 clear_config([:instance, :public], false)
808 clear_config([:restrict_unauthenticated, :timelines])
810 for local <- [true, false] do
811 res_conn = get(conn, "#{base_uri}?local=#{local}")
813 assert json_response(res_conn, :unauthorized) == error_response
816 ensure_authenticated_access(base_uri)
819 test "with `%{local: true, federated: true}`, returns 403 for unauthenticated users", %{
822 error_response: error_response
824 clear_config([:restrict_unauthenticated, :timelines, :local], true)
825 clear_config([:restrict_unauthenticated, :timelines, :federated], true)
827 for local <- [true, false] do
828 res_conn = get(conn, "#{base_uri}?local=#{local}")
830 assert json_response(res_conn, :unauthorized) == error_response
833 ensure_authenticated_access(base_uri)
836 test "with `%{local: false, federated: true}`, forbids unauthenticated access to federated timeline",
837 %{conn: conn, base_uri: base_uri, error_response: error_response} do
838 clear_config([:restrict_unauthenticated, :timelines, :local], false)
839 clear_config([:restrict_unauthenticated, :timelines, :federated], true)
841 res_conn = get(conn, "#{base_uri}?local=true")
842 assert length(json_response(res_conn, 200)) == 1
844 res_conn = get(conn, "#{base_uri}?local=false")
845 assert json_response(res_conn, :unauthorized) == error_response
847 ensure_authenticated_access(base_uri)
850 test "with `%{local: true, federated: false}`, forbids unauthenticated access to public timeline" <>
851 "(but not to local public activities which are delivered as part of federated timeline)",
852 %{conn: conn, base_uri: base_uri, error_response: error_response} do
853 clear_config([:restrict_unauthenticated, :timelines, :local], true)
854 clear_config([:restrict_unauthenticated, :timelines, :federated], false)
856 res_conn = get(conn, "#{base_uri}?local=true")
857 assert json_response(res_conn, :unauthorized) == error_response
859 # Note: local activities get delivered as part of federated timeline
860 res_conn = get(conn, "#{base_uri}?local=false")
861 assert length(json_response(res_conn, 200)) == 2
863 ensure_authenticated_access(base_uri)
867 defp create_remote_activity(user) do
872 "https://www.w3.org/ns/activitystreams#Public",
873 User.ap_followers(user)
879 insert(:note_activity, %{
882 "https://www.w3.org/ns/activitystreams#Public",
883 User.ap_followers(user)
890 defp create_with_media_activity(user) do
891 obj = insert(:attachment_note, user: user)
893 insert(:note_activity, %{
895 recipients: ["https://www.w3.org/ns/activitystreams#Public", User.ap_followers(user)],