Merge branch 'develop' into feature/report-notes
[akkoma] / test / web / mastodon_api / controllers / timeline_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.TimelineControllerTest do
6 use Pleroma.Web.ConnCase
7
8 import Pleroma.Factory
9 import Tesla.Mock
10
11 alias Pleroma.Config
12 alias Pleroma.User
13 alias Pleroma.Web.CommonAPI
14
15 clear_config([:instance, :public])
16
17 setup do
18 mock(fn env -> apply(HttpRequestMock, :request, [env]) end)
19 :ok
20 end
21
22 describe "home" do
23 test "the home timeline", %{conn: conn} do
24 user = insert(:user)
25 following = insert(:user)
26
27 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
28
29 conn =
30 conn
31 |> assign(:user, user)
32 |> get("/api/v1/timelines/home")
33
34 assert Enum.empty?(json_response(conn, :ok))
35
36 {:ok, user} = User.follow(user, following)
37
38 conn =
39 build_conn()
40 |> assign(:user, user)
41 |> get("/api/v1/timelines/home")
42
43 assert [%{"content" => "test"}] = json_response(conn, :ok)
44 end
45
46 test "the home timeline when the direct messages are excluded", %{conn: conn} do
47 user = insert(:user)
48 {:ok, public_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "public"})
49 {:ok, direct_activity} = CommonAPI.post(user, %{"status" => ".", "visibility" => "direct"})
50
51 {:ok, unlisted_activity} =
52 CommonAPI.post(user, %{"status" => ".", "visibility" => "unlisted"})
53
54 {:ok, private_activity} =
55 CommonAPI.post(user, %{"status" => ".", "visibility" => "private"})
56
57 conn =
58 conn
59 |> assign(:user, user)
60 |> get("/api/v1/timelines/home", %{"exclude_visibilities" => ["direct"]})
61
62 assert status_ids = json_response(conn, :ok) |> Enum.map(& &1["id"])
63 assert public_activity.id in status_ids
64 assert unlisted_activity.id in status_ids
65 assert private_activity.id in status_ids
66 refute direct_activity.id in status_ids
67 end
68 end
69
70 describe "public" do
71 @tag capture_log: true
72 test "the public timeline", %{conn: conn} do
73 following = insert(:user)
74
75 {:ok, _activity} = CommonAPI.post(following, %{"status" => "test"})
76
77 _activity = insert(:note_activity, local: false)
78
79 conn = get(conn, "/api/v1/timelines/public", %{"local" => "False"})
80
81 assert length(json_response(conn, :ok)) == 2
82
83 conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "True"})
84
85 assert [%{"content" => "test"}] = json_response(conn, :ok)
86
87 conn = get(build_conn(), "/api/v1/timelines/public", %{"local" => "1"})
88
89 assert [%{"content" => "test"}] = json_response(conn, :ok)
90 end
91
92 test "the public timeline when public is set to false", %{conn: conn} do
93 Config.put([:instance, :public], false)
94
95 assert %{"error" => "This resource requires authentication."} ==
96 conn
97 |> get("/api/v1/timelines/public", %{"local" => "False"})
98 |> json_response(:forbidden)
99 end
100
101 test "the public timeline includes only public statuses for an authenticated user" do
102 user = insert(:user)
103
104 conn =
105 build_conn()
106 |> assign(:user, user)
107
108 {:ok, _activity} = CommonAPI.post(user, %{"status" => "test"})
109 {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "private"})
110 {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "unlisted"})
111 {:ok, _activity} = CommonAPI.post(user, %{"status" => "test", "visibility" => "direct"})
112
113 res_conn = get(conn, "/api/v1/timelines/public")
114 assert length(json_response(res_conn, 200)) == 1
115 end
116 end
117
118 describe "direct" do
119 test "direct timeline", %{conn: conn} do
120 user_one = insert(:user)
121 user_two = insert(:user)
122
123 {:ok, user_two} = User.follow(user_two, user_one)
124
125 {:ok, direct} =
126 CommonAPI.post(user_one, %{
127 "status" => "Hi @#{user_two.nickname}!",
128 "visibility" => "direct"
129 })
130
131 {:ok, _follower_only} =
132 CommonAPI.post(user_one, %{
133 "status" => "Hi @#{user_two.nickname}!",
134 "visibility" => "private"
135 })
136
137 # Only direct should be visible here
138 res_conn =
139 conn
140 |> assign(:user, user_two)
141 |> get("api/v1/timelines/direct")
142
143 [status] = json_response(res_conn, :ok)
144
145 assert %{"visibility" => "direct"} = status
146 assert status["url"] != direct.data["id"]
147
148 # User should be able to see their own direct message
149 res_conn =
150 build_conn()
151 |> assign(:user, user_one)
152 |> get("api/v1/timelines/direct")
153
154 [status] = json_response(res_conn, :ok)
155
156 assert %{"visibility" => "direct"} = status
157
158 # Both should be visible here
159 res_conn =
160 conn
161 |> assign(:user, user_two)
162 |> get("api/v1/timelines/home")
163
164 [_s1, _s2] = json_response(res_conn, :ok)
165
166 # Test pagination
167 Enum.each(1..20, fn _ ->
168 {:ok, _} =
169 CommonAPI.post(user_one, %{
170 "status" => "Hi @#{user_two.nickname}!",
171 "visibility" => "direct"
172 })
173 end)
174
175 res_conn =
176 conn
177 |> assign(:user, user_two)
178 |> get("api/v1/timelines/direct")
179
180 statuses = json_response(res_conn, :ok)
181 assert length(statuses) == 20
182
183 res_conn =
184 conn
185 |> assign(:user, user_two)
186 |> get("api/v1/timelines/direct", %{max_id: List.last(statuses)["id"]})
187
188 [status] = json_response(res_conn, :ok)
189
190 assert status["url"] != direct.data["id"]
191 end
192
193 test "doesn't include DMs from blocked users", %{conn: conn} do
194 blocker = insert(:user)
195 blocked = insert(:user)
196 user = insert(:user)
197 {:ok, _user_relationship} = User.block(blocker, blocked)
198
199 {:ok, _blocked_direct} =
200 CommonAPI.post(blocked, %{
201 "status" => "Hi @#{blocker.nickname}!",
202 "visibility" => "direct"
203 })
204
205 {:ok, direct} =
206 CommonAPI.post(user, %{
207 "status" => "Hi @#{blocker.nickname}!",
208 "visibility" => "direct"
209 })
210
211 res_conn =
212 conn
213 |> assign(:user, user)
214 |> get("api/v1/timelines/direct")
215
216 [status] = json_response(res_conn, :ok)
217 assert status["id"] == direct.id
218 end
219 end
220
221 describe "list" do
222 test "list timeline", %{conn: conn} do
223 user = insert(:user)
224 other_user = insert(:user)
225 {:ok, _activity_one} = CommonAPI.post(user, %{"status" => "Marisa is cute."})
226 {:ok, activity_two} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
227 {:ok, list} = Pleroma.List.create("name", user)
228 {:ok, list} = Pleroma.List.follow(list, other_user)
229
230 conn =
231 conn
232 |> assign(:user, user)
233 |> get("/api/v1/timelines/list/#{list.id}")
234
235 assert [%{"id" => id}] = json_response(conn, :ok)
236
237 assert id == to_string(activity_two.id)
238 end
239
240 test "list timeline does not leak non-public statuses for unfollowed users", %{conn: conn} do
241 user = insert(:user)
242 other_user = insert(:user)
243 {:ok, activity_one} = CommonAPI.post(other_user, %{"status" => "Marisa is cute."})
244
245 {:ok, _activity_two} =
246 CommonAPI.post(other_user, %{
247 "status" => "Marisa is cute.",
248 "visibility" => "private"
249 })
250
251 {:ok, list} = Pleroma.List.create("name", user)
252 {:ok, list} = Pleroma.List.follow(list, other_user)
253
254 conn =
255 conn
256 |> assign(:user, user)
257 |> get("/api/v1/timelines/list/#{list.id}")
258
259 assert [%{"id" => id}] = json_response(conn, :ok)
260
261 assert id == to_string(activity_one.id)
262 end
263 end
264
265 describe "hashtag" do
266 @tag capture_log: true
267 test "hashtag timeline", %{conn: conn} do
268 following = insert(:user)
269
270 {:ok, activity} = CommonAPI.post(following, %{"status" => "test #2hu"})
271
272 nconn = get(conn, "/api/v1/timelines/tag/2hu")
273
274 assert [%{"id" => id}] = json_response(nconn, :ok)
275
276 assert id == to_string(activity.id)
277
278 # works for different capitalization too
279 nconn = get(conn, "/api/v1/timelines/tag/2HU")
280
281 assert [%{"id" => id}] = json_response(nconn, :ok)
282
283 assert id == to_string(activity.id)
284 end
285
286 test "multi-hashtag timeline", %{conn: conn} do
287 user = insert(:user)
288
289 {:ok, activity_test} = CommonAPI.post(user, %{"status" => "#test"})
290 {:ok, activity_test1} = CommonAPI.post(user, %{"status" => "#test #test1"})
291 {:ok, activity_none} = CommonAPI.post(user, %{"status" => "#test #none"})
292
293 any_test = get(conn, "/api/v1/timelines/tag/test", %{"any" => ["test1"]})
294
295 [status_none, status_test1, status_test] = json_response(any_test, :ok)
296
297 assert to_string(activity_test.id) == status_test["id"]
298 assert to_string(activity_test1.id) == status_test1["id"]
299 assert to_string(activity_none.id) == status_none["id"]
300
301 restricted_test =
302 get(conn, "/api/v1/timelines/tag/test", %{"all" => ["test1"], "none" => ["none"]})
303
304 assert [status_test1] == json_response(restricted_test, :ok)
305
306 all_test = get(conn, "/api/v1/timelines/tag/test", %{"all" => ["none"]})
307
308 assert [status_none] == json_response(all_test, :ok)
309 end
310 end
311 end