Merge branch 'fix/put-repeats-at-activitypub-outbox' into 'develop'
[akkoma] / test / user_test.exs
1 defmodule Pleroma.UserTest do
2 alias Pleroma.Builders.UserBuilder
3 alias Pleroma.{User, Repo, Activity}
4 alias Pleroma.Web.OStatus
5 alias Pleroma.Web.Websub.WebsubClientSubscription
6 alias Pleroma.Web.CommonAPI
7 use Pleroma.DataCase
8
9 import Pleroma.Factory
10 import Ecto.Query
11
12 test "ap_id returns the activity pub id for the user" do
13 user = UserBuilder.build()
14
15 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
16
17 assert expected_ap_id == User.ap_id(user)
18 end
19
20 test "ap_followers returns the followers collection for the user" do
21 user = UserBuilder.build()
22
23 expected_followers_collection = "#{User.ap_id(user)}/followers"
24
25 assert expected_followers_collection == User.ap_followers(user)
26 end
27
28 test "follow takes a user and another user" do
29 user = insert(:user)
30 followed = insert(:user)
31
32 {:ok, user} = User.follow(user, followed)
33
34 user = Repo.get(User, user.id)
35
36 followed = User.get_by_ap_id(followed.ap_id)
37 assert followed.info["follower_count"] == 1
38
39 assert User.ap_followers(followed) in user.following
40 end
41
42 test "can't follow a deactivated users" do
43 user = insert(:user)
44 followed = insert(:user, info: %{"deactivated" => true})
45
46 {:error, _} = User.follow(user, followed)
47 end
48
49 test "can't follow a user who blocked us" do
50 blocker = insert(:user)
51 blockee = insert(:user)
52
53 {:ok, blocker} = User.block(blocker, blockee)
54
55 {:error, _} = User.follow(blockee, blocker)
56 end
57
58 # This is a somewhat useless test.
59 # test "following a remote user will ensure a websub subscription is present" do
60 # user = insert(:user)
61 # {:ok, followed} = OStatus.make_user("shp@social.heldscal.la")
62
63 # assert followed.local == false
64
65 # {:ok, user} = User.follow(user, followed)
66 # assert User.ap_followers(followed) in user.following
67
68 # query = from w in WebsubClientSubscription,
69 # where: w.topic == ^followed.info["topic"]
70 # websub = Repo.one(query)
71
72 # assert websub
73 # end
74
75 test "unfollow takes a user and another user" do
76 followed = insert(:user)
77 user = insert(:user, %{following: [User.ap_followers(followed)]})
78
79 {:ok, user, _activity} = User.unfollow(user, followed)
80
81 user = Repo.get(User, user.id)
82
83 assert user.following == []
84 end
85
86 test "unfollow doesn't unfollow yourself" do
87 user = insert(:user)
88
89 {:error, _} = User.unfollow(user, user)
90
91 user = Repo.get(User, user.id)
92 assert user.following == [user.ap_id]
93 end
94
95 test "test if a user is following another user" do
96 followed = insert(:user)
97 user = insert(:user, %{following: [User.ap_followers(followed)]})
98
99 assert User.following?(user, followed)
100 refute User.following?(followed, user)
101 end
102
103 describe "user registration" do
104 @full_user_data %{
105 bio: "A guy",
106 name: "my name",
107 nickname: "nick",
108 password: "test",
109 password_confirmation: "test",
110 email: "email@example.com"
111 }
112
113 test "it requires an email, name, nickname and password, bio is optional" do
114 @full_user_data
115 |> Map.keys()
116 |> Enum.each(fn key ->
117 params = Map.delete(@full_user_data, key)
118 changeset = User.register_changeset(%User{}, params)
119
120 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
121 end)
122 end
123
124 test "it sets the password_hash, ap_id and following fields" do
125 changeset = User.register_changeset(%User{}, @full_user_data)
126
127 assert changeset.valid?
128
129 assert is_binary(changeset.changes[:password_hash])
130 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
131
132 assert changeset.changes[:following] == [
133 User.ap_followers(%User{nickname: @full_user_data.nickname})
134 ]
135
136 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
137 end
138 end
139
140 describe "fetching a user from nickname or trying to build one" do
141 test "gets an existing user" do
142 user = insert(:user)
143 fetched_user = User.get_or_fetch_by_nickname(user.nickname)
144
145 assert user == fetched_user
146 end
147
148 test "gets an existing user, case insensitive" do
149 user = insert(:user, nickname: "nick")
150 fetched_user = User.get_or_fetch_by_nickname("NICK")
151
152 assert user == fetched_user
153 end
154
155 test "fetches an external user via ostatus if no user exists" do
156 fetched_user = User.get_or_fetch_by_nickname("shp@social.heldscal.la")
157 assert fetched_user.nickname == "shp@social.heldscal.la"
158 end
159
160 test "returns nil if no user could be fetched" do
161 fetched_user = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
162 assert fetched_user == nil
163 end
164
165 test "returns nil for nonexistant local user" do
166 fetched_user = User.get_or_fetch_by_nickname("nonexistant")
167 assert fetched_user == nil
168 end
169 end
170
171 test "returns an ap_id for a user" do
172 user = insert(:user)
173
174 assert User.ap_id(user) ==
175 Pleroma.Web.Router.Helpers.o_status_url(
176 Pleroma.Web.Endpoint,
177 :feed_redirect,
178 user.nickname
179 )
180 end
181
182 test "returns an ap_followers link for a user" do
183 user = insert(:user)
184
185 assert User.ap_followers(user) ==
186 Pleroma.Web.Router.Helpers.o_status_url(
187 Pleroma.Web.Endpoint,
188 :feed_redirect,
189 user.nickname
190 ) <> "/followers"
191 end
192
193 describe "remote user creation changeset" do
194 @valid_remote %{
195 bio: "hello",
196 name: "Someone",
197 nickname: "a@b.de",
198 ap_id: "http...",
199 info: %{some: "info"},
200 avatar: %{some: "avatar"}
201 }
202
203 test "it confirms validity" do
204 cs = User.remote_user_creation(@valid_remote)
205 assert cs.valid?
206 end
207
208 test "it sets the follower_adress" do
209 cs = User.remote_user_creation(@valid_remote)
210 # remote users get a fake local follower address
211 assert cs.changes.follower_address ==
212 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
213 end
214
215 test "it enforces the fqn format for nicknames" do
216 cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"})
217 assert cs.changes.local == false
218 assert cs.changes.avatar
219 refute cs.valid?
220 end
221
222 test "it has required fields" do
223 [:name, :nickname, :ap_id]
224 |> Enum.each(fn field ->
225 cs = User.remote_user_creation(Map.delete(@valid_remote, field))
226 refute cs.valid?
227 end)
228 end
229
230 test "it restricts some sizes" do
231 [bio: 5000, name: 100]
232 |> Enum.each(fn {field, size} ->
233 string = String.pad_leading(".", size)
234 cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
235 assert cs.valid?
236
237 string = String.pad_leading(".", size + 1)
238 cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
239 refute cs.valid?
240 end)
241 end
242 end
243
244 describe "followers and friends" do
245 test "gets all followers for a given user" do
246 user = insert(:user)
247 follower_one = insert(:user)
248 follower_two = insert(:user)
249 not_follower = insert(:user)
250
251 {:ok, follower_one} = User.follow(follower_one, user)
252 {:ok, follower_two} = User.follow(follower_two, user)
253
254 {:ok, res} = User.get_followers(user)
255
256 assert Enum.member?(res, follower_one)
257 assert Enum.member?(res, follower_two)
258 refute Enum.member?(res, not_follower)
259 end
260
261 test "gets all friends (followed users) for a given user" do
262 user = insert(:user)
263 followed_one = insert(:user)
264 followed_two = insert(:user)
265 not_followed = insert(:user)
266
267 {:ok, user} = User.follow(user, followed_one)
268 {:ok, user} = User.follow(user, followed_two)
269
270 {:ok, res} = User.get_friends(user)
271
272 followed_one = User.get_by_ap_id(followed_one.ap_id)
273 followed_two = User.get_by_ap_id(followed_two.ap_id)
274 assert Enum.member?(res, followed_one)
275 assert Enum.member?(res, followed_two)
276 refute Enum.member?(res, not_followed)
277 end
278 end
279
280 describe "updating note and follower count" do
281 test "it sets the info->note_count property" do
282 note = insert(:note)
283
284 user = User.get_by_ap_id(note.data["actor"])
285
286 assert user.info["note_count"] == nil
287
288 {:ok, user} = User.update_note_count(user)
289
290 assert user.info["note_count"] == 1
291 end
292
293 test "it increases the info->note_count property" do
294 note = insert(:note)
295 user = User.get_by_ap_id(note.data["actor"])
296
297 assert user.info["note_count"] == nil
298
299 {:ok, user} = User.increase_note_count(user)
300
301 assert user.info["note_count"] == 1
302
303 {:ok, user} = User.increase_note_count(user)
304
305 assert user.info["note_count"] == 2
306 end
307
308 test "it decreases the info->note_count property" do
309 note = insert(:note)
310 user = User.get_by_ap_id(note.data["actor"])
311
312 assert user.info["note_count"] == nil
313
314 {:ok, user} = User.increase_note_count(user)
315
316 assert user.info["note_count"] == 1
317
318 {:ok, user} = User.decrease_note_count(user)
319
320 assert user.info["note_count"] == 0
321
322 {:ok, user} = User.decrease_note_count(user)
323
324 assert user.info["note_count"] == 0
325 end
326
327 test "it sets the info->follower_count property" do
328 user = insert(:user)
329 follower = insert(:user)
330
331 User.follow(follower, user)
332
333 assert user.info["follower_count"] == nil
334
335 {:ok, user} = User.update_follower_count(user)
336
337 assert user.info["follower_count"] == 1
338 end
339 end
340
341 describe "blocks" do
342 test "it blocks people" do
343 user = insert(:user)
344 blocked_user = insert(:user)
345
346 refute User.blocks?(user, blocked_user)
347
348 {:ok, user} = User.block(user, blocked_user)
349
350 assert User.blocks?(user, blocked_user)
351 end
352
353 test "it unblocks users" do
354 user = insert(:user)
355 blocked_user = insert(:user)
356
357 {:ok, user} = User.block(user, blocked_user)
358 {:ok, user} = User.unblock(user, blocked_user)
359
360 refute User.blocks?(user, blocked_user)
361 end
362
363 test "blocks tear down cyclical follow relationships" do
364 blocker = insert(:user)
365 blocked = insert(:user)
366
367 {:ok, blocker} = User.follow(blocker, blocked)
368 {:ok, blocked} = User.follow(blocked, blocker)
369
370 assert User.following?(blocker, blocked)
371 assert User.following?(blocked, blocker)
372
373 {:ok, blocker} = User.block(blocker, blocked)
374 blocked = Repo.get(User, blocked.id)
375
376 assert User.blocks?(blocker, blocked)
377
378 refute User.following?(blocker, blocked)
379 refute User.following?(blocked, blocker)
380 end
381
382 test "blocks tear down blocker->blocked follow relationships" do
383 blocker = insert(:user)
384 blocked = insert(:user)
385
386 {:ok, blocker} = User.follow(blocker, blocked)
387
388 assert User.following?(blocker, blocked)
389 refute User.following?(blocked, blocker)
390
391 {:ok, blocker} = User.block(blocker, blocked)
392 blocked = Repo.get(User, blocked.id)
393
394 assert User.blocks?(blocker, blocked)
395
396 refute User.following?(blocker, blocked)
397 refute User.following?(blocked, blocker)
398 end
399
400 test "blocks tear down blocked->blocker follow relationships" do
401 blocker = insert(:user)
402 blocked = insert(:user)
403
404 {:ok, blocked} = User.follow(blocked, blocker)
405
406 refute User.following?(blocker, blocked)
407 assert User.following?(blocked, blocker)
408
409 {:ok, blocker} = User.block(blocker, blocked)
410 blocked = Repo.get(User, blocked.id)
411
412 assert User.blocks?(blocker, blocked)
413
414 refute User.following?(blocker, blocked)
415 refute User.following?(blocked, blocker)
416 end
417 end
418
419 describe "domain blocking" do
420 test "blocks domains" do
421 user = insert(:user)
422 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
423
424 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
425
426 assert User.blocks?(user, collateral_user)
427 end
428
429 test "unblocks domains" do
430 user = insert(:user)
431 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
432
433 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
434 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
435
436 refute User.blocks?(user, collateral_user)
437 end
438 end
439
440 test "get recipients from activity" do
441 actor = insert(:user)
442 user = insert(:user, local: true)
443 user_two = insert(:user, local: false)
444 addressed = insert(:user, local: true)
445 addressed_remote = insert(:user, local: false)
446
447 {:ok, activity} =
448 CommonAPI.post(actor, %{
449 "status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
450 })
451
452 assert [addressed] == User.get_recipients_from_activity(activity)
453
454 {:ok, user} = User.follow(user, actor)
455 {:ok, _user_two} = User.follow(user_two, actor)
456 recipients = User.get_recipients_from_activity(activity)
457 assert length(recipients) == 2
458 assert user in recipients
459 assert addressed in recipients
460 end
461
462 test ".deactivate deactivates a user" do
463 user = insert(:user)
464 assert false == !!user.info["deactivated"]
465 {:ok, user} = User.deactivate(user)
466 assert true == user.info["deactivated"]
467 end
468
469 test ".delete deactivates a user, all follow relationships and all create activities" do
470 user = insert(:user)
471 followed = insert(:user)
472 follower = insert(:user)
473
474 {:ok, user} = User.follow(user, followed)
475 {:ok, follower} = User.follow(follower, user)
476
477 {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
478 {:ok, activity_two} = CommonAPI.post(follower, %{"status" => "3hu"})
479
480 {:ok, _, _} = CommonAPI.favorite(activity_two.id, user)
481 {:ok, _, _} = CommonAPI.favorite(activity.id, follower)
482 {:ok, _, _} = CommonAPI.repeat(activity.id, follower)
483
484 :ok = User.delete(user)
485
486 followed = Repo.get(User, followed.id)
487 follower = Repo.get(User, follower.id)
488 user = Repo.get(User, user.id)
489
490 assert user.info["deactivated"]
491
492 refute User.following?(user, followed)
493 refute User.following?(followed, follower)
494
495 # TODO: Remove favorites, repeats, delete activities.
496
497 refute Repo.get(Activity, activity.id)
498 end
499
500 test "get_public_key_for_ap_id fetches a user that's not in the db" do
501 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
502 end
503
504 test "insert or update a user from given data" do
505 user = insert(:user, %{nickname: "nick@name.de"})
506 data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
507
508 assert {:ok, %User{}} = User.insert_or_update_user(data)
509 end
510 end