1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 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
13 alias Pleroma.Web.CommonAPI
14 alias Pleroma.Web.OStatus
16 clear_config([:instance, :public])
19 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
24 test "the home timeline", %{conn: conn} do
26 following = insert(:user)
28 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
32 |> assign(:user, user)
33 |> get("/api/v1/timelines/home")
35 assert Enum.empty?(json_response(conn, :ok))
37 {:ok, user} = User.follow(user, following)
41 |> assign(:user, user)
42 |> get("/api/v1/timelines/home")
44 assert [%{"content" => "test"}] = json_response(conn, :ok)
47 test "the home timeline when the direct messages are excluded", %{conn: conn} do
49 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
50 {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
52 {:ok, unlisted_activity} =
53 CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
55 {:ok, private_activity} =
56 CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
60 |> assign(:user, user)
61 |> get("/api/v1/timelines/home", %{"exclude_visibilities" => ["direct"]})
63 assert status_ids = json_response(conn, :ok) |> Enum.map(& &1["id"])
64 assert public_activity.id in status_ids
65 assert unlisted_activity.id in status_ids
66 assert private_activity.id in status_ids
67 refute direct_activity.id in status_ids
72 @tag capture_log: true
73 test "the public timeline", %{conn: conn} do
74 following = insert(:user)
76 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
79 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
81 conn = get(conn, "/api/v1/timelines/public", %{"local" => "False"})
83 assert length(json_response(conn, :ok)) == 2
85 conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "True"})
87 assert [%{"content" => "test"}] = json_response(conn, :ok)
89 conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "1"})
91 assert [%{"content" => "test"}] = json_response(conn, :ok)
94 test "the public timeline when public is set to false", %{conn: conn} do
95 Config.put([:instance, :public], false)
97 assert %{"error" => "This resource requires authentication."} ==
99 |> get("/api/v1/timelines/public", %{"local" => "False"})
100 |> json_response(:forbidden)
103 test "the public timeline includes only public statuses for an authenticated user" do
108 |> assign(:user, user)
110 {:ok, _activity} = CommonAPI.post(user, %{"status" => "test"})
111 {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "private"})
112 {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "unlisted"})
113 {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
115 res_conn = get(conn, "/api/v1/timelines/public")
116 assert length(json_response(res_conn, 200)) == 1
121 test "direct timeline", %{conn: conn} do
122 user_one = insert(:user)
123 user_two = insert(:user)
125 {:ok, user_two} = User.follow(user_two, user_one)
128 CommonAPI.post(user_one, %{
129 "status" => "Hi @#{user_two.nickname}!",
130 "visibility" => "direct"
133 {:ok, _follower_only} =
134 CommonAPI.post(user_one, %{
135 "status" => "Hi @#{user_two.nickname}!",
136 "visibility" => "private"
139 # Only direct should be visible here
142 |> assign(:user, user_two)
143 |> get("api/v1/timelines/direct")
145 [status] = json_response(res_conn, :ok)
147 assert %{"visibility" => "direct"} = status
148 assert status["url"] != direct.data["id"]
150 # User should be able to see their own direct message
153 |> assign(:user, user_one)
154 |> get("api/v1/timelines/direct")
156 [status] = json_response(res_conn, :ok)
158 assert %{"visibility" => "direct"} = status
160 # Both should be visible here
163 |> assign(:user, user_two)
164 |> get("api/v1/timelines/home")
166 [_s1, _s2] = json_response(res_conn, :ok)
169 Enum.each(1..20, fn _ ->
171 CommonAPI.post(user_one, %{
172 "status" => "Hi @#{user_two.nickname}!",
173 "visibility" => "direct"
179 |> assign(:user, user_two)
180 |> get("api/v1/timelines/direct")
182 statuses = json_response(res_conn, :ok)
183 assert length(statuses) == 20
187 |> assign(:user, user_two)
188 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
190 [status] = json_response(res_conn, :ok)
192 assert status["url"] != direct.data["id"]
195 test "doesn't include DMs from blocked users", %{conn: conn} do
196 blocker = insert(:user)
197 blocked = insert(:user)
199 {:ok, blocker} = User.block(blocker, blocked)
201 {:ok, _blocked_direct} =
202 CommonAPI.post(blocked, %{
203 "status" => "Hi @#{blocker.nickname}!",
204 "visibility" => "direct"
208 CommonAPI.post(user, %{
209 "status" => "Hi @#{blocker.nickname}!",
210 "visibility" => "direct"
215 |> assign(:user, user)
216 |> get("api/v1/timelines/direct")
218 [status] = json_response(res_conn, :ok)
219 assert status["id"] == direct.id
224 test "list timeline", %{conn: conn} do
226 other_user = insert(:user)
227 {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."})
228 {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
229 {:ok, list} = Pleroma.List.create("name", user)
230 {:ok, list} = Pleroma.List.follow(list, other_user)
234 |> assign(:user, user)
235 |> get("/api/v1/timelines/list/#{list.id}")
237 assert [%{"id" => id}] = json_response(conn, :ok)
239 assert id == to_string(activity_two.id)
242 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
244 other_user = insert(:user)
245 {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
247 {:ok, _activity_two} =
248 CommonAPI.post(other_user, %{
249 "status" => "Marisa is cute.",
250 "visibility" => "private"
253 {:ok, list} = Pleroma.List.create("name", user)
254 {:ok, list} = Pleroma.List.follow(list, other_user)
258 |> assign(:user, user)
259 |> get("/api/v1/timelines/list/#{list.id}")
261 assert [%{"id" => id}] = json_response(conn, :ok)
263 assert id == to_string(activity_one.id)
267 describe "hashtag" do
268 @tag capture_log: true
269 test "hashtag timeline", %{conn: conn} do
270 following = insert(:user)
272 {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
275 OStatus.fetch_activity_from_url("https://shitposter.club/notice/2827873")
277 nconn = get(conn, "/api/v1/timelines/tag/2hu")
279 assert [%{"id" => id}] = json_response(nconn, :ok)
281 assert id == to_string(activity.id)
283 # works for different capitalization too
284 nconn = get(conn, "/api/v1/timelines/tag/2HU")
286 assert [%{"id" => id}] = json_response(nconn, :ok)
288 assert id == to_string(activity.id)
291 test "multi-hashtag timeline", %{conn: conn} do
294 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
295 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
296 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
298 any_test = get(conn, "/api/v1/timelines/tag/test", %{"any" => ["test1"]})
300 [status_none, status_test1, status_test] = json_response(any_test, :ok)
302 assert to_string(activity_test.id) == status_test["id"]
303 assert to_string(activity_test1.id) == status_test1["id"]
304 assert to_string(activity_none.id) == status_none["id"]
307 get(conn, "/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
309 assert [status_test1] == json_response(restricted_test, :ok)
311 all_test = get(conn, "/api/v1/timelines/tag/test", %{"all" => ["none"]})
313 assert [status_none] == json_response(all_test, :ok)