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