Format files
[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 test "local users do not automatically follow local locked accounts" do
59 follower = insert(:user, info: %{locked: true})
60 followed = insert(:user, info: %{locked: true})
61
62 {:ok, follower} = User.maybe_direct_follow(follower, followed)
63
64 refute User.following?(follower, followed)
65 end
66
67 # This is a somewhat useless test.
68 # test "following a remote user will ensure a websub subscription is present" do
69 # user = insert(:user)
70 # {:ok, followed} = OStatus.make_user("shp@social.heldscal.la")
71
72 # assert followed.local == false
73
74 # {:ok, user} = User.follow(user, followed)
75 # assert User.ap_followers(followed) in user.following
76
77 # query = from w in WebsubClientSubscription,
78 # where: w.topic == ^followed.info["topic"]
79 # websub = Repo.one(query)
80
81 # assert websub
82 # end
83
84 test "unfollow takes a user and another user" do
85 followed = insert(:user)
86 user = insert(:user, %{following: [User.ap_followers(followed)]})
87
88 {:ok, user, _activity} = User.unfollow(user, followed)
89
90 user = Repo.get(User, user.id)
91
92 assert user.following == []
93 end
94
95 test "unfollow doesn't unfollow yourself" do
96 user = insert(:user)
97
98 {:error, _} = User.unfollow(user, user)
99
100 user = Repo.get(User, user.id)
101 assert user.following == [user.ap_id]
102 end
103
104 test "test if a user is following another user" do
105 followed = insert(:user)
106 user = insert(:user, %{following: [User.ap_followers(followed)]})
107
108 assert User.following?(user, followed)
109 refute User.following?(followed, user)
110 end
111
112 describe "user registration" do
113 @full_user_data %{
114 bio: "A guy",
115 name: "my name",
116 nickname: "nick",
117 password: "test",
118 password_confirmation: "test",
119 email: "email@example.com"
120 }
121
122 test "it requires an email, name, nickname and password, bio is optional" do
123 @full_user_data
124 |> Map.keys()
125 |> Enum.each(fn key ->
126 params = Map.delete(@full_user_data, key)
127 changeset = User.register_changeset(%User{}, params)
128
129 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
130 end)
131 end
132
133 test "it sets the password_hash, ap_id and following fields" do
134 changeset = User.register_changeset(%User{}, @full_user_data)
135
136 assert changeset.valid?
137
138 assert is_binary(changeset.changes[:password_hash])
139 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
140
141 assert changeset.changes[:following] == [
142 User.ap_followers(%User{nickname: @full_user_data.nickname})
143 ]
144
145 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
146 end
147 end
148
149 describe "fetching a user from nickname or trying to build one" do
150 test "gets an existing user" do
151 user = insert(:user)
152 fetched_user = User.get_or_fetch_by_nickname(user.nickname)
153
154 assert user == fetched_user
155 end
156
157 test "gets an existing user, case insensitive" do
158 user = insert(:user, nickname: "nick")
159 fetched_user = User.get_or_fetch_by_nickname("NICK")
160
161 assert user == fetched_user
162 end
163
164 test "fetches an external user via ostatus if no user exists" do
165 fetched_user = User.get_or_fetch_by_nickname("shp@social.heldscal.la")
166 assert fetched_user.nickname == "shp@social.heldscal.la"
167 end
168
169 test "returns nil if no user could be fetched" do
170 fetched_user = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
171 assert fetched_user == nil
172 end
173
174 test "returns nil for nonexistant local user" do
175 fetched_user = User.get_or_fetch_by_nickname("nonexistant")
176 assert fetched_user == nil
177 end
178
179 test "updates an existing user, if stale" do
180 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
181
182 orig_user =
183 insert(
184 :user,
185 local: false,
186 nickname: "admin@mastodon.example.org",
187 ap_id: "http://mastodon.example.org/users/admin",
188 last_refreshed_at: a_week_ago,
189 info: %{}
190 )
191
192 assert orig_user.last_refreshed_at == a_week_ago
193
194 user = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
195 assert user.info.source_data["endpoints"]
196
197 refute user.last_refreshed_at == orig_user.last_refreshed_at
198 end
199 end
200
201 test "returns an ap_id for a user" do
202 user = insert(:user)
203
204 assert User.ap_id(user) ==
205 Pleroma.Web.Router.Helpers.o_status_url(
206 Pleroma.Web.Endpoint,
207 :feed_redirect,
208 user.nickname
209 )
210 end
211
212 test "returns an ap_followers link for a user" do
213 user = insert(:user)
214
215 assert User.ap_followers(user) ==
216 Pleroma.Web.Router.Helpers.o_status_url(
217 Pleroma.Web.Endpoint,
218 :feed_redirect,
219 user.nickname
220 ) <> "/followers"
221 end
222
223 describe "remote user creation changeset" do
224 @valid_remote %{
225 bio: "hello",
226 name: "Someone",
227 nickname: "a@b.de",
228 ap_id: "http...",
229 info: %{some: "info"},
230 avatar: %{some: "avatar"}
231 }
232
233 test "it confirms validity" do
234 cs = User.remote_user_creation(@valid_remote)
235 assert cs.valid?
236 end
237
238 test "it sets the follower_adress" do
239 cs = User.remote_user_creation(@valid_remote)
240 # remote users get a fake local follower address
241 assert cs.changes.follower_address ==
242 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
243 end
244
245 test "it enforces the fqn format for nicknames" do
246 cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"})
247 assert cs.changes.local == false
248 assert cs.changes.avatar
249 refute cs.valid?
250 end
251
252 test "it has required fields" do
253 [:name, :ap_id]
254 |> Enum.each(fn field ->
255 cs = User.remote_user_creation(Map.delete(@valid_remote, field))
256 refute cs.valid?
257 end)
258 end
259
260 test "it restricts some sizes" do
261 [bio: 5000, name: 100]
262 |> Enum.each(fn {field, size} ->
263 string = String.pad_leading(".", size)
264 cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
265 assert cs.valid?
266
267 string = String.pad_leading(".", size + 1)
268 cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
269 refute cs.valid?
270 end)
271 end
272 end
273
274 describe "followers and friends" do
275 test "gets all followers for a given user" do
276 user = insert(:user)
277 follower_one = insert(:user)
278 follower_two = insert(:user)
279 not_follower = insert(:user)
280
281 {:ok, follower_one} = User.follow(follower_one, user)
282 {:ok, follower_two} = User.follow(follower_two, user)
283
284 {:ok, res} = User.get_followers(user)
285
286 assert Enum.member?(res, follower_one)
287 assert Enum.member?(res, follower_two)
288 refute Enum.member?(res, not_follower)
289 end
290
291 test "gets all friends (followed users) for a given user" do
292 user = insert(:user)
293 followed_one = insert(:user)
294 followed_two = insert(:user)
295 not_followed = insert(:user)
296
297 {:ok, user} = User.follow(user, followed_one)
298 {:ok, user} = User.follow(user, followed_two)
299
300 {:ok, res} = User.get_friends(user)
301
302 followed_one = User.get_by_ap_id(followed_one.ap_id)
303 followed_two = User.get_by_ap_id(followed_two.ap_id)
304 assert Enum.member?(res, followed_one)
305 assert Enum.member?(res, followed_two)
306 refute Enum.member?(res, not_followed)
307 end
308 end
309
310 describe "updating note and follower count" do
311 test "it sets the info->note_count property" do
312 note = insert(:note)
313
314 user = User.get_by_ap_id(note.data["actor"])
315
316 assert user.info.note_count == 0
317
318 {:ok, user} = User.update_note_count(user)
319
320 assert user.info.note_count == 1
321 end
322
323 test "it increases the info->note_count property" do
324 note = insert(:note)
325 user = User.get_by_ap_id(note.data["actor"])
326
327 assert user.info.note_count == 0
328
329 {:ok, user} = User.increase_note_count(user)
330
331 assert user.info.note_count == 1
332
333 {:ok, user} = User.increase_note_count(user)
334
335 assert user.info.note_count == 2
336 end
337
338 test "it decreases the info->note_count property" do
339 note = insert(:note)
340 user = User.get_by_ap_id(note.data["actor"])
341
342 assert user.info.note_count == 0
343
344 {:ok, user} = User.increase_note_count(user)
345
346 assert user.info.note_count == 1
347
348 {:ok, user} = User.decrease_note_count(user)
349
350 assert user.info.note_count == 0
351
352 {:ok, user} = User.decrease_note_count(user)
353
354 assert user.info.note_count == 0
355 end
356
357 test "it sets the info->follower_count property" do
358 user = insert(:user)
359 follower = insert(:user)
360
361 User.follow(follower, user)
362
363 assert user.info.follower_count == 0
364
365 {:ok, user} = User.update_follower_count(user)
366
367 assert user.info.follower_count == 1
368 end
369 end
370
371 describe "blocks" do
372 test "it blocks people" do
373 user = insert(:user)
374 blocked_user = insert(:user)
375
376 refute User.blocks?(user, blocked_user)
377
378 {:ok, user} = User.block(user, blocked_user)
379
380 assert User.blocks?(user, blocked_user)
381 end
382
383 test "it unblocks users" do
384 user = insert(:user)
385 blocked_user = insert(:user)
386
387 {:ok, user} = User.block(user, blocked_user)
388 {:ok, user} = User.unblock(user, blocked_user)
389
390 refute User.blocks?(user, blocked_user)
391 end
392
393 test "blocks tear down cyclical follow relationships" do
394 blocker = insert(:user)
395 blocked = insert(:user)
396
397 {:ok, blocker} = User.follow(blocker, blocked)
398 {:ok, blocked} = User.follow(blocked, blocker)
399
400 assert User.following?(blocker, blocked)
401 assert User.following?(blocked, blocker)
402
403 {:ok, blocker} = User.block(blocker, blocked)
404 blocked = Repo.get(User, blocked.id)
405
406 assert User.blocks?(blocker, blocked)
407
408 refute User.following?(blocker, blocked)
409 refute User.following?(blocked, blocker)
410 end
411
412 test "blocks tear down blocker->blocked follow relationships" do
413 blocker = insert(:user)
414 blocked = insert(:user)
415
416 {:ok, blocker} = User.follow(blocker, blocked)
417
418 assert User.following?(blocker, blocked)
419 refute User.following?(blocked, blocker)
420
421 {:ok, blocker} = User.block(blocker, blocked)
422 blocked = Repo.get(User, blocked.id)
423
424 assert User.blocks?(blocker, blocked)
425
426 refute User.following?(blocker, blocked)
427 refute User.following?(blocked, blocker)
428 end
429
430 test "blocks tear down blocked->blocker follow relationships" do
431 blocker = insert(:user)
432 blocked = insert(:user)
433
434 {:ok, blocked} = User.follow(blocked, blocker)
435
436 refute User.following?(blocker, blocked)
437 assert User.following?(blocked, blocker)
438
439 {:ok, blocker} = User.block(blocker, blocked)
440 blocked = Repo.get(User, blocked.id)
441
442 assert User.blocks?(blocker, blocked)
443
444 refute User.following?(blocker, blocked)
445 refute User.following?(blocked, blocker)
446 end
447 end
448
449 describe "domain blocking" do
450 test "blocks domains" do
451 user = insert(:user)
452 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
453
454 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
455
456 assert User.blocks?(user, collateral_user)
457 end
458
459 test "unblocks domains" do
460 user = insert(:user)
461 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
462
463 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
464 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
465
466 refute User.blocks?(user, collateral_user)
467 end
468 end
469
470 test "get recipients from activity" do
471 actor = insert(:user)
472 user = insert(:user, local: true)
473 user_two = insert(:user, local: false)
474 addressed = insert(:user, local: true)
475 addressed_remote = insert(:user, local: false)
476
477 {:ok, activity} =
478 CommonAPI.post(actor, %{
479 "status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
480 })
481
482 assert [addressed] == User.get_recipients_from_activity(activity)
483
484 {:ok, user} = User.follow(user, actor)
485 {:ok, _user_two} = User.follow(user_two, actor)
486 recipients = User.get_recipients_from_activity(activity)
487 assert length(recipients) == 2
488 assert user in recipients
489 assert addressed in recipients
490 end
491
492 test ".deactivate can de-activate then re-activate a user" do
493 user = insert(:user)
494 assert false == user.info.deactivated
495 {:ok, user} = User.deactivate(user)
496 assert true == user.info.deactivated
497 {:ok, user} = User.deactivate(user, false)
498 assert false == user.info.deactivated
499 end
500
501 test ".delete deactivates a user, all follow relationships and all create activities" do
502 user = insert(:user)
503 followed = insert(:user)
504 follower = insert(:user)
505
506 {:ok, user} = User.follow(user, followed)
507 {:ok, follower} = User.follow(follower, user)
508
509 {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
510 {:ok, activity_two} = CommonAPI.post(follower, %{"status" => "3hu"})
511
512 {:ok, _, _} = CommonAPI.favorite(activity_two.id, user)
513 {:ok, _, _} = CommonAPI.favorite(activity.id, follower)
514 {:ok, _, _} = CommonAPI.repeat(activity.id, follower)
515
516 {:ok, _} = User.delete(user)
517
518 followed = Repo.get(User, followed.id)
519 follower = Repo.get(User, follower.id)
520 user = Repo.get(User, user.id)
521
522 assert user.info.deactivated
523
524 refute User.following?(user, followed)
525 refute User.following?(followed, follower)
526
527 # TODO: Remove favorites, repeats, delete activities.
528
529 refute Repo.get(Activity, activity.id)
530 end
531
532 test "get_public_key_for_ap_id fetches a user that's not in the db" do
533 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
534 end
535
536 test "insert or update a user from given data" do
537 user = insert(:user, %{nickname: "nick@name.de"})
538 data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
539
540 assert {:ok, %User{}} = User.insert_or_update_user(data)
541 end
542
543 describe "per-user rich-text filtering" do
544 test "html_filter_policy returns nil when rich-text is enabled" do
545 user = insert(:user)
546
547 assert nil == User.html_filter_policy(user)
548 end
549
550 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
551 user = insert(:user, %{info: %{no_rich_text: true}})
552
553 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
554 end
555 end
556
557 describe "caching" do
558 test "invalidate_cache works" do
559 user = insert(:user)
560 user_info = User.get_cached_user_info(user)
561
562 User.invalidate_cache(user)
563
564 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
565 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
566 {:ok, nil} = Cachex.get(:user_cache, "user_info:#{user.id}")
567 end
568
569 test "User.delete() plugs any possible zombie objects" do
570 user = insert(:user)
571
572 {:ok, _} = User.delete(user)
573
574 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
575
576 assert cached_user != user
577
578 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
579
580 assert cached_user != user
581 end
582 end
583
584 describe "User.search" do
585 test "finds a user, ranking by similarity" do
586 user = insert(:user, %{name: "lain"})
587 user_two = insert(:user, %{name: "ean"})
588 user_three = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social"})
589 user_four = insert(:user, %{nickname: "lain@pleroma.soykaf.com"})
590
591 assert user_four ==
592 User.search("lain@ple") |> List.first() |> Map.put(:search_distance, nil)
593 end
594 end
595 end