Merge branch 'activitypub-likes' into 'develop'
[akkoma] / test / web / activity_pub / activity_pub_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
6 use Pleroma.Web.ConnCase
7 import Pleroma.Factory
8 alias Pleroma.Web.ActivityPub.{UserView, ObjectView}
9 alias Pleroma.{Object, Repo, User}
10 alias Pleroma.Activity
11
12 setup_all do
13 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
14 :ok
15 end
16
17 describe "/relay" do
18 test "with the relay active, it returns the relay user", %{conn: conn} do
19 res =
20 conn
21 |> get(activity_pub_path(conn, :relay))
22 |> json_response(200)
23
24 assert res["id"] =~ "/relay"
25 end
26
27 test "with the relay disabled, it returns 404", %{conn: conn} do
28 Pleroma.Config.put([:instance, :allow_relay], false)
29
30 conn
31 |> get(activity_pub_path(conn, :relay))
32 |> json_response(404)
33 |> assert
34
35 Pleroma.Config.put([:instance, :allow_relay], true)
36 end
37 end
38
39 describe "/users/:nickname" do
40 test "it returns a json representation of the user", %{conn: conn} do
41 user = insert(:user)
42
43 conn =
44 conn
45 |> put_req_header("accept", "application/activity+json")
46 |> get("/users/#{user.nickname}")
47
48 user = Repo.get(User, user.id)
49
50 assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
51 end
52 end
53
54 describe "/object/:uuid" do
55 test "it returns a json representation of the object", %{conn: conn} do
56 note = insert(:note)
57 uuid = String.split(note.data["id"], "/") |> List.last()
58
59 conn =
60 conn
61 |> put_req_header("accept", "application/activity+json")
62 |> get("/objects/#{uuid}")
63
64 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
65 end
66
67 test "it returns 404 for non-public messages", %{conn: conn} do
68 note = insert(:direct_note)
69 uuid = String.split(note.data["id"], "/") |> List.last()
70
71 conn =
72 conn
73 |> put_req_header("accept", "application/activity+json")
74 |> get("/objects/#{uuid}")
75
76 assert json_response(conn, 404)
77 end
78
79 test "it returns 404 for tombstone objects", %{conn: conn} do
80 tombstone = insert(:tombstone)
81 uuid = String.split(tombstone.data["id"], "/") |> List.last()
82
83 conn =
84 conn
85 |> put_req_header("accept", "application/activity+json")
86 |> get("/objects/#{uuid}")
87
88 assert json_response(conn, 404)
89 end
90 end
91
92 describe "/object/:uuid/likes" do
93 test "it returns the like activities in a collection", %{conn: conn} do
94 like = insert(:like_activity)
95 uuid = String.split(like.data["object"], "/") |> List.last()
96
97 result =
98 conn
99 |> put_req_header("accept", "application/activity+json")
100 |> get("/objects/#{uuid}/likes")
101 |> json_response(200)
102
103 assert List.first(result["first"]["orderedItems"])["id"] == like.data["id"]
104 end
105 end
106
107 describe "/activities/:uuid" do
108 test "it returns a json representation of the activity", %{conn: conn} do
109 activity = insert(:note_activity)
110 uuid = String.split(activity.data["id"], "/") |> List.last()
111
112 conn =
113 conn
114 |> put_req_header("accept", "application/activity+json")
115 |> get("/activities/#{uuid}")
116
117 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: activity})
118 end
119
120 test "it returns 404 for non-public activities", %{conn: conn} do
121 activity = insert(:direct_note_activity)
122 uuid = String.split(activity.data["id"], "/") |> List.last()
123
124 conn =
125 conn
126 |> put_req_header("accept", "application/activity+json")
127 |> get("/activities/#{uuid}")
128
129 assert json_response(conn, 404)
130 end
131 end
132
133 describe "/inbox" do
134 test "it inserts an incoming activity into the database", %{conn: conn} do
135 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
136
137 conn =
138 conn
139 |> assign(:valid_signature, true)
140 |> put_req_header("content-type", "application/activity+json")
141 |> post("/inbox", data)
142
143 assert "ok" == json_response(conn, 200)
144 :timer.sleep(500)
145 assert Activity.get_by_ap_id(data["id"])
146 end
147 end
148
149 describe "/users/:nickname/inbox" do
150 test "it inserts an incoming activity into the database", %{conn: conn} do
151 user = insert(:user)
152
153 data =
154 File.read!("test/fixtures/mastodon-post-activity.json")
155 |> Poison.decode!()
156 |> Map.put("bcc", [user.ap_id])
157
158 conn =
159 conn
160 |> assign(:valid_signature, true)
161 |> put_req_header("content-type", "application/activity+json")
162 |> post("/users/#{user.nickname}/inbox", data)
163
164 assert "ok" == json_response(conn, 200)
165 :timer.sleep(500)
166 assert Activity.get_by_ap_id(data["id"])
167 end
168
169 test "it rejects reads from other users", %{conn: conn} do
170 user = insert(:user)
171 otheruser = insert(:user)
172
173 conn =
174 conn
175 |> assign(:user, otheruser)
176 |> put_req_header("accept", "application/activity+json")
177 |> get("/users/#{user.nickname}/inbox")
178
179 assert json_response(conn, 403)
180 end
181
182 test "it returns a note activity in a collection", %{conn: conn} do
183 note_activity = insert(:direct_note_activity)
184 user = User.get_cached_by_ap_id(hd(note_activity.data["to"]))
185
186 conn =
187 conn
188 |> assign(:user, user)
189 |> put_req_header("accept", "application/activity+json")
190 |> get("/users/#{user.nickname}/inbox")
191
192 assert response(conn, 200) =~ note_activity.data["object"]["content"]
193 end
194 end
195
196 describe "/users/:nickname/outbox" do
197 test "it returns a note activity in a collection", %{conn: conn} do
198 note_activity = insert(:note_activity)
199 user = User.get_cached_by_ap_id(note_activity.data["actor"])
200
201 conn =
202 conn
203 |> put_req_header("accept", "application/activity+json")
204 |> get("/users/#{user.nickname}/outbox")
205
206 assert response(conn, 200) =~ note_activity.data["object"]["content"]
207 end
208
209 test "it returns an announce activity in a collection", %{conn: conn} do
210 announce_activity = insert(:announce_activity)
211 user = User.get_cached_by_ap_id(announce_activity.data["actor"])
212
213 conn =
214 conn
215 |> put_req_header("accept", "application/activity+json")
216 |> get("/users/#{user.nickname}/outbox")
217
218 assert response(conn, 200) =~ announce_activity.data["object"]
219 end
220
221 test "it rejects posts from other users", %{conn: conn} do
222 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
223 user = insert(:user)
224 otheruser = insert(:user)
225
226 conn =
227 conn
228 |> assign(:user, otheruser)
229 |> put_req_header("content-type", "application/activity+json")
230 |> post("/users/#{user.nickname}/outbox", data)
231
232 assert json_response(conn, 403)
233 end
234
235 test "it inserts an incoming create activity into the database", %{conn: conn} do
236 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
237 user = insert(:user)
238
239 conn =
240 conn
241 |> assign(:user, user)
242 |> put_req_header("content-type", "application/activity+json")
243 |> post("/users/#{user.nickname}/outbox", data)
244
245 result = json_response(conn, 201)
246 assert Activity.get_by_ap_id(result["id"])
247 end
248
249 test "it rejects an incoming activity with bogus type", %{conn: conn} do
250 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
251 user = insert(:user)
252
253 data =
254 data
255 |> Map.put("type", "BadType")
256
257 conn =
258 conn
259 |> assign(:user, user)
260 |> put_req_header("content-type", "application/activity+json")
261 |> post("/users/#{user.nickname}/outbox", data)
262
263 assert json_response(conn, 400)
264 end
265
266 test "it erects a tombstone when receiving a delete activity", %{conn: conn} do
267 note_activity = insert(:note_activity)
268 user = User.get_cached_by_ap_id(note_activity.data["actor"])
269
270 data = %{
271 type: "Delete",
272 object: %{
273 id: note_activity.data["object"]["id"]
274 }
275 }
276
277 conn =
278 conn
279 |> assign(:user, user)
280 |> put_req_header("content-type", "application/activity+json")
281 |> post("/users/#{user.nickname}/outbox", data)
282
283 result = json_response(conn, 201)
284 assert Activity.get_by_ap_id(result["id"])
285
286 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
287 assert object
288 assert object.data["type"] == "Tombstone"
289 end
290
291 test "it rejects delete activity of object from other actor", %{conn: conn} do
292 note_activity = insert(:note_activity)
293 user = insert(:user)
294
295 data = %{
296 type: "Delete",
297 object: %{
298 id: note_activity.data["object"]["id"]
299 }
300 }
301
302 conn =
303 conn
304 |> assign(:user, user)
305 |> put_req_header("content-type", "application/activity+json")
306 |> post("/users/#{user.nickname}/outbox", data)
307
308 assert json_response(conn, 400)
309 end
310
311 test "it increases like count when receiving a like action", %{conn: conn} do
312 note_activity = insert(:note_activity)
313 user = User.get_cached_by_ap_id(note_activity.data["actor"])
314
315 data = %{
316 type: "Like",
317 object: %{
318 id: note_activity.data["object"]["id"]
319 }
320 }
321
322 conn =
323 conn
324 |> assign(:user, user)
325 |> put_req_header("content-type", "application/activity+json")
326 |> post("/users/#{user.nickname}/outbox", data)
327
328 result = json_response(conn, 201)
329 assert Activity.get_by_ap_id(result["id"])
330
331 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
332 assert object
333 assert object.data["like_count"] == 1
334 end
335 end
336
337 describe "/users/:nickname/followers" do
338 test "it returns the followers in a collection", %{conn: conn} do
339 user = insert(:user)
340 user_two = insert(:user)
341 User.follow(user, user_two)
342
343 result =
344 conn
345 |> get("/users/#{user_two.nickname}/followers")
346 |> json_response(200)
347
348 assert result["first"]["orderedItems"] == [user.ap_id]
349 end
350
351 test "it returns returns empty if the user has 'hide_network' set", %{conn: conn} do
352 user = insert(:user)
353 user_two = insert(:user, %{info: %{hide_network: true}})
354 User.follow(user, user_two)
355
356 result =
357 conn
358 |> get("/users/#{user_two.nickname}/followers")
359 |> json_response(200)
360
361 assert result["first"]["orderedItems"] == []
362 assert result["totalItems"] == 1
363 end
364
365 test "it works for more than 10 users", %{conn: conn} do
366 user = insert(:user)
367
368 Enum.each(1..15, fn _ ->
369 other_user = insert(:user)
370 User.follow(other_user, user)
371 end)
372
373 result =
374 conn
375 |> get("/users/#{user.nickname}/followers")
376 |> json_response(200)
377
378 assert length(result["first"]["orderedItems"]) == 10
379 assert result["first"]["totalItems"] == 15
380 assert result["totalItems"] == 15
381
382 result =
383 conn
384 |> get("/users/#{user.nickname}/followers?page=2")
385 |> json_response(200)
386
387 assert length(result["orderedItems"]) == 5
388 assert result["totalItems"] == 15
389 end
390 end
391
392 describe "/users/:nickname/following" do
393 test "it returns the following in a collection", %{conn: conn} do
394 user = insert(:user)
395 user_two = insert(:user)
396 User.follow(user, user_two)
397
398 result =
399 conn
400 |> get("/users/#{user.nickname}/following")
401 |> json_response(200)
402
403 assert result["first"]["orderedItems"] == [user_two.ap_id]
404 end
405
406 test "it returns returns empty if the user has 'hide_network' set", %{conn: conn} do
407 user = insert(:user, %{info: %{hide_network: true}})
408 user_two = insert(:user)
409 User.follow(user, user_two)
410
411 result =
412 conn
413 |> get("/users/#{user.nickname}/following")
414 |> json_response(200)
415
416 assert result["first"]["orderedItems"] == []
417 assert result["totalItems"] == 1
418 end
419
420 test "it works for more than 10 users", %{conn: conn} do
421 user = insert(:user)
422
423 Enum.each(1..15, fn _ ->
424 user = Repo.get(User, user.id)
425 other_user = insert(:user)
426 User.follow(user, other_user)
427 end)
428
429 result =
430 conn
431 |> get("/users/#{user.nickname}/following")
432 |> json_response(200)
433
434 assert length(result["first"]["orderedItems"]) == 10
435 assert result["first"]["totalItems"] == 15
436 assert result["totalItems"] == 15
437
438 result =
439 conn
440 |> get("/users/#{user.nickname}/following?page=2")
441 |> json_response(200)
442
443 assert length(result["orderedItems"]) == 5
444 assert result["totalItems"] == 15
445 end
446 end
447 end