9cabb501c169c3dabb87d381a7d029949ca09d8c
[akkoma] / test / user_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.UserTest do
6 alias Pleroma.Activity
7 alias Pleroma.Builders.UserBuilder
8 alias Pleroma.Object
9 alias Pleroma.Repo
10 alias Pleroma.Tests.ObanHelpers
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
14
15 use Pleroma.DataCase
16 use Oban.Testing, repo: Pleroma.Repo
17
18 import Pleroma.Factory
19 import ExUnit.CaptureLog
20 import Swoosh.TestAssertions
21
22 setup_all do
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
24 :ok
25 end
26
27 setup do: clear_config([:instance, :account_activation_required])
28
29 describe "service actors" do
30 test "returns updated invisible actor" do
31 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
32 followers_uri = "#{uri}/followers"
33
34 insert(
35 :user,
36 %{
37 nickname: "relay",
38 invisible: false,
39 local: true,
40 ap_id: uri,
41 follower_address: followers_uri
42 }
43 )
44
45 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
46 assert actor.invisible
47 end
48
49 test "returns relay user" do
50 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
51 followers_uri = "#{uri}/followers"
52
53 assert %User{
54 nickname: "relay",
55 invisible: true,
56 local: true,
57 ap_id: ^uri,
58 follower_address: ^followers_uri
59 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
60
61 assert capture_log(fn ->
62 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
63 end) =~ "Cannot create service actor:"
64 end
65
66 test "returns invisible actor" do
67 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
68 followers_uri = "#{uri}/followers"
69 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
70
71 assert %User{
72 nickname: "internal.fetch-test",
73 invisible: true,
74 local: true,
75 ap_id: ^uri,
76 follower_address: ^followers_uri
77 } = user
78
79 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
80 assert user.id == user2.id
81 end
82 end
83
84 describe "AP ID user relationships" do
85 setup do
86 {:ok, user: insert(:user)}
87 end
88
89 test "outgoing_relationships_ap_ids/1", %{user: user} do
90 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
91
92 ap_ids_by_rel =
93 Enum.into(
94 rel_types,
95 %{},
96 fn rel_type ->
97 rel_records =
98 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
99
100 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
101 {rel_type, Enum.sort(ap_ids)}
102 end
103 )
104
105 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
106 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
107
108 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
109 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
110
111 assert ap_ids_by_rel[:notification_mute] ==
112 Enum.sort(User.notification_muted_users_ap_ids(user))
113
114 assert ap_ids_by_rel[:notification_mute] ==
115 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
116
117 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
118
119 assert ap_ids_by_rel[:reblog_mute] ==
120 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
121
122 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
123
124 assert ap_ids_by_rel[:inverse_subscription] ==
125 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
126
127 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
128
129 assert ap_ids_by_rel ==
130 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
131 end
132 end
133
134 describe "when tags are nil" do
135 test "tagging a user" do
136 user = insert(:user, %{tags: nil})
137 user = User.tag(user, ["cool", "dude"])
138
139 assert "cool" in user.tags
140 assert "dude" in user.tags
141 end
142
143 test "untagging a user" do
144 user = insert(:user, %{tags: nil})
145 user = User.untag(user, ["cool", "dude"])
146
147 assert user.tags == []
148 end
149 end
150
151 test "ap_id returns the activity pub id for the user" do
152 user = UserBuilder.build()
153
154 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
155
156 assert expected_ap_id == User.ap_id(user)
157 end
158
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
161
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
163
164 assert expected_followers_collection == User.ap_followers(user)
165 end
166
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
169
170 expected_followers_collection = "#{User.ap_id(user)}/following"
171
172 assert expected_followers_collection == User.ap_following(user)
173 end
174
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, locked: true)
178 follower = insert(:user)
179
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
182
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
185
186 assert activity
187 end
188
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
193
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
197
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
199
200 assert [^pending_follower] = User.get_follow_requests(locked)
201 end
202
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, locked: true)
205 pending_follower = insert(:user, %{deactivated: true})
206
207 CommonAPI.follow(pending_follower, locked)
208
209 assert true == pending_follower.deactivated
210 assert [] = User.get_follow_requests(locked)
211 end
212
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, locked: true)
215 follower = insert(:user)
216
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
219
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
222 end
223
224 test "follow_all follows mutliple users" do
225 user = insert(:user)
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
232
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
235
236 {:ok, user} = User.follow(user, followed_zero)
237
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
239
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
246 end
247
248 test "follow_all follows mutliple users without duplicating" do
249 user = insert(:user)
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
253
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
256
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
259 end
260
261 test "follow takes a user and another user" do
262 user = insert(:user)
263 followed = insert(:user)
264
265 {:ok, user} = User.follow(user, followed)
266
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
269
270 assert followed.follower_count == 1
271 assert user.following_count == 1
272
273 assert User.ap_followers(followed) in User.following(user)
274 end
275
276 test "can't follow a deactivated users" do
277 user = insert(:user)
278 followed = insert(:user, %{deactivated: true})
279
280 {:error, _} = User.follow(user, followed)
281 end
282
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
286
287 {:ok, _user_relationship} = User.block(blocker, blockee)
288
289 {:error, _} = User.follow(blockee, blocker)
290 end
291
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
295
296 {:ok, _user_relationship} = User.block(blocker, blocked)
297
298 {:error, _} = User.subscribe(blocked, blocker)
299 end
300
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, locked: true)
303 followed = insert(:user, locked: true)
304
305 {:ok, follower} = User.maybe_direct_follow(follower, followed)
306
307 refute User.following?(follower, followed)
308 end
309
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
312
313 test "unfollow with syncronizes external user" do
314 Pleroma.Config.put([:instance, :external_user_synchronization], true)
315
316 followed =
317 insert(:user,
318 nickname: "fuser1",
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
322 )
323
324 user =
325 insert(:user, %{
326 local: false,
327 nickname: "fuser2",
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
331 })
332
333 {:ok, user} = User.follow(user, followed, :follow_accept)
334
335 {:ok, user, _activity} = User.unfollow(user, followed)
336
337 user = User.get_cached_by_id(user.id)
338
339 assert User.following(user) == []
340 end
341
342 test "unfollow takes a user and another user" do
343 followed = insert(:user)
344 user = insert(:user)
345
346 {:ok, user} = User.follow(user, followed, :follow_accept)
347
348 assert User.following(user) == [user.follower_address, followed.follower_address]
349
350 {:ok, user, _activity} = User.unfollow(user, followed)
351
352 assert User.following(user) == [user.follower_address]
353 end
354
355 test "unfollow doesn't unfollow yourself" do
356 user = insert(:user)
357
358 {:error, _} = User.unfollow(user, user)
359
360 assert User.following(user) == [user.follower_address]
361 end
362 end
363
364 test "test if a user is following another user" do
365 followed = insert(:user)
366 user = insert(:user)
367 User.follow(user, followed, :follow_accept)
368
369 assert User.following?(user, followed)
370 refute User.following?(followed, user)
371 end
372
373 test "fetches correct profile for nickname beginning with number" do
374 # Use old-style integer ID to try to reproduce the problem
375 user = insert(:user, %{id: 1080})
376 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
377 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
378 end
379
380 describe "user registration" do
381 @full_user_data %{
382 bio: "A guy",
383 name: "my name",
384 nickname: "nick",
385 password: "test",
386 password_confirmation: "test",
387 email: "email@example.com"
388 }
389
390 setup do: clear_config([:instance, :autofollowed_nicknames])
391 setup do: clear_config([:welcome])
392 setup do: clear_config([:instance, :account_activation_required])
393
394 test "it autofollows accounts that are set for it" do
395 user = insert(:user)
396 remote_user = insert(:user, %{local: false})
397
398 Pleroma.Config.put([:instance, :autofollowed_nicknames], [
399 user.nickname,
400 remote_user.nickname
401 ])
402
403 cng = User.register_changeset(%User{}, @full_user_data)
404
405 {:ok, registered_user} = User.register(cng)
406
407 assert User.following?(registered_user, user)
408 refute User.following?(registered_user, remote_user)
409 end
410
411 test "it sends a welcome message if it is set" do
412 welcome_user = insert(:user)
413 Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
414 Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
415 Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message")
416
417 cng = User.register_changeset(%User{}, @full_user_data)
418 {:ok, registered_user} = User.register(cng)
419 ObanHelpers.perform_all()
420
421 activity = Repo.one(Pleroma.Activity)
422 assert registered_user.ap_id in activity.recipients
423 assert Object.normalize(activity).data["content"] =~ "direct message"
424 assert activity.actor == welcome_user.ap_id
425 end
426
427 test "it sends a welcome chat message if it is set" do
428 welcome_user = insert(:user)
429 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
430 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
431 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
432
433 cng = User.register_changeset(%User{}, @full_user_data)
434 {:ok, registered_user} = User.register(cng)
435 ObanHelpers.perform_all()
436
437 activity = Repo.one(Pleroma.Activity)
438 assert registered_user.ap_id in activity.recipients
439 assert Object.normalize(activity).data["content"] =~ "chat message"
440 assert activity.actor == welcome_user.ap_id
441 end
442
443 setup do:
444 clear_config(:mrf_simple,
445 media_removal: [],
446 media_nsfw: [],
447 federated_timeline_removal: [],
448 report_removal: [],
449 reject: [],
450 followers_only: [],
451 accept: [],
452 avatar_removal: [],
453 banner_removal: [],
454 reject_deletes: []
455 )
456
457 setup do:
458 clear_config(:mrf,
459 policies: [
460 Pleroma.Web.ActivityPub.MRF.SimplePolicy
461 ]
462 )
463
464 test "it sends a welcome chat message when Simple policy applied to local instance" do
465 Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"])
466
467 welcome_user = insert(:user)
468 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
469 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
470 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
471
472 cng = User.register_changeset(%User{}, @full_user_data)
473 {:ok, registered_user} = User.register(cng)
474 ObanHelpers.perform_all()
475
476 activity = Repo.one(Pleroma.Activity)
477 assert registered_user.ap_id in activity.recipients
478 assert Object.normalize(activity).data["content"] =~ "chat message"
479 assert activity.actor == welcome_user.ap_id
480 end
481
482 test "it sends a welcome email message if it is set" do
483 welcome_user = insert(:user)
484 Pleroma.Config.put([:welcome, :email, :enabled], true)
485 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
486
487 Pleroma.Config.put(
488 [:welcome, :email, :subject],
489 "Hello, welcome to cool site: <%= instance_name %>"
490 )
491
492 instance_name = Pleroma.Config.get([:instance, :name])
493
494 cng = User.register_changeset(%User{}, @full_user_data)
495 {:ok, registered_user} = User.register(cng)
496 ObanHelpers.perform_all()
497
498 assert_email_sent(
499 from: {instance_name, welcome_user.email},
500 to: {registered_user.name, registered_user.email},
501 subject: "Hello, welcome to cool site: #{instance_name}",
502 html_body: "Welcome to #{instance_name}"
503 )
504 end
505
506 test "it sends a confirm email" do
507 Pleroma.Config.put([:instance, :account_activation_required], true)
508
509 cng = User.register_changeset(%User{}, @full_user_data)
510 {:ok, registered_user} = User.register(cng)
511 ObanHelpers.perform_all()
512
513 Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
514 # temporary hackney fix until hackney max_connections bug is fixed
515 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
516 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
517 |> assert_email_sent()
518 end
519
520 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
521 Pleroma.Config.put([:instance, :account_activation_required], true)
522
523 @full_user_data
524 |> Map.keys()
525 |> Enum.each(fn key ->
526 params = Map.delete(@full_user_data, key)
527 changeset = User.register_changeset(%User{}, params)
528
529 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
530 end)
531 end
532
533 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
534 Pleroma.Config.put([:instance, :account_activation_required], false)
535
536 @full_user_data
537 |> Map.keys()
538 |> Enum.each(fn key ->
539 params = Map.delete(@full_user_data, key)
540 changeset = User.register_changeset(%User{}, params)
541
542 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
543 end)
544 end
545
546 test "it restricts certain nicknames" do
547 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
548
549 assert is_bitstring(restricted_name)
550
551 params =
552 @full_user_data
553 |> Map.put(:nickname, restricted_name)
554
555 changeset = User.register_changeset(%User{}, params)
556
557 refute changeset.valid?
558 end
559
560 test "it blocks blacklisted email domains" do
561 clear_config([User, :email_blacklist], ["trolling.world"])
562
563 # Block with match
564 params = Map.put(@full_user_data, :email, "troll@trolling.world")
565 changeset = User.register_changeset(%User{}, params)
566 refute changeset.valid?
567
568 # Block with subdomain match
569 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
570 changeset = User.register_changeset(%User{}, params)
571 refute changeset.valid?
572
573 # Pass with different domains that are similar
574 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
575 changeset = User.register_changeset(%User{}, params)
576 assert changeset.valid?
577
578 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
579 changeset = User.register_changeset(%User{}, params)
580 assert changeset.valid?
581 end
582
583 test "it sets the password_hash and ap_id" do
584 changeset = User.register_changeset(%User{}, @full_user_data)
585
586 assert changeset.valid?
587
588 assert is_binary(changeset.changes[:password_hash])
589 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
590
591 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
592 end
593
594 test "it sets the 'accepts_chat_messages' set to true" do
595 changeset = User.register_changeset(%User{}, @full_user_data)
596 assert changeset.valid?
597
598 {:ok, user} = Repo.insert(changeset)
599
600 assert user.accepts_chat_messages
601 end
602
603 test "it creates a confirmed user" do
604 changeset = User.register_changeset(%User{}, @full_user_data)
605 assert changeset.valid?
606
607 {:ok, user} = Repo.insert(changeset)
608
609 refute user.confirmation_pending
610 end
611 end
612
613 describe "user registration, with :account_activation_required" do
614 @full_user_data %{
615 bio: "A guy",
616 name: "my name",
617 nickname: "nick",
618 password: "test",
619 password_confirmation: "test",
620 email: "email@example.com"
621 }
622 setup do: clear_config([:instance, :account_activation_required], true)
623
624 test "it creates unconfirmed user" do
625 changeset = User.register_changeset(%User{}, @full_user_data)
626 assert changeset.valid?
627
628 {:ok, user} = Repo.insert(changeset)
629
630 assert user.confirmation_pending
631 assert user.confirmation_token
632 end
633
634 test "it creates confirmed user if :confirmed option is given" do
635 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
636 assert changeset.valid?
637
638 {:ok, user} = Repo.insert(changeset)
639
640 refute user.confirmation_pending
641 refute user.confirmation_token
642 end
643 end
644
645 describe "user registration, with :account_approval_required" do
646 @full_user_data %{
647 bio: "A guy",
648 name: "my name",
649 nickname: "nick",
650 password: "test",
651 password_confirmation: "test",
652 email: "email@example.com",
653 registration_reason: "I'm a cool guy :)"
654 }
655 setup do: clear_config([:instance, :account_approval_required], true)
656
657 test "it creates unapproved user" do
658 changeset = User.register_changeset(%User{}, @full_user_data)
659 assert changeset.valid?
660
661 {:ok, user} = Repo.insert(changeset)
662
663 assert user.approval_pending
664 assert user.registration_reason == "I'm a cool guy :)"
665 end
666
667 test "it restricts length of registration reason" do
668 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
669
670 assert is_integer(reason_limit)
671
672 params =
673 @full_user_data
674 |> Map.put(
675 :registration_reason,
676 "Quia et nesciunt dolores numquam ipsam nisi sapiente soluta. Ullam repudiandae nisi quam porro officiis officiis ad. Consequatur animi velit ex quia. Odit voluptatem perferendis quia ut nisi. Dignissimos sit soluta atque aliquid dolorem ut dolorum ut. Labore voluptates iste iusto amet voluptatum earum. Ad fugit illum nam eos ut nemo. Pariatur ea fuga non aspernatur. Dignissimos debitis officia corporis est nisi ab et. Atque itaque alias eius voluptas minus. Accusamus numquam tempore occaecati in."
677 )
678
679 changeset = User.register_changeset(%User{}, params)
680
681 refute changeset.valid?
682 end
683 end
684
685 describe "get_or_fetch/1" do
686 test "gets an existing user by nickname" do
687 user = insert(:user)
688 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
689
690 assert user == fetched_user
691 end
692
693 test "gets an existing user by ap_id" do
694 ap_id = "http://mastodon.example.org/users/admin"
695
696 user =
697 insert(
698 :user,
699 local: false,
700 nickname: "admin@mastodon.example.org",
701 ap_id: ap_id
702 )
703
704 {:ok, fetched_user} = User.get_or_fetch(ap_id)
705 freshed_user = refresh_record(user)
706 assert freshed_user == fetched_user
707 end
708 end
709
710 describe "fetching a user from nickname or trying to build one" do
711 test "gets an existing user" do
712 user = insert(:user)
713 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
714
715 assert user == fetched_user
716 end
717
718 test "gets an existing user, case insensitive" do
719 user = insert(:user, nickname: "nick")
720 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
721
722 assert user == fetched_user
723 end
724
725 test "gets an existing user by fully qualified nickname" do
726 user = insert(:user)
727
728 {:ok, fetched_user} =
729 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
730
731 assert user == fetched_user
732 end
733
734 test "gets an existing user by fully qualified nickname, case insensitive" do
735 user = insert(:user, nickname: "nick")
736 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
737
738 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
739
740 assert user == fetched_user
741 end
742
743 @tag capture_log: true
744 test "returns nil if no user could be fetched" do
745 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
746 assert fetched_user == "not found nonexistant@social.heldscal.la"
747 end
748
749 test "returns nil for nonexistant local user" do
750 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
751 assert fetched_user == "not found nonexistant"
752 end
753
754 test "updates an existing user, if stale" do
755 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
756
757 orig_user =
758 insert(
759 :user,
760 local: false,
761 nickname: "admin@mastodon.example.org",
762 ap_id: "http://mastodon.example.org/users/admin",
763 last_refreshed_at: a_week_ago
764 )
765
766 assert orig_user.last_refreshed_at == a_week_ago
767
768 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
769
770 assert user.inbox
771
772 refute user.last_refreshed_at == orig_user.last_refreshed_at
773 end
774
775 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
776 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
777
778 orig_user =
779 insert(
780 :user,
781 local: false,
782 nickname: "admin@mastodon.example.org",
783 ap_id: "http://mastodon.example.org/users/harinezumigari",
784 last_refreshed_at: a_week_ago
785 )
786
787 assert orig_user.last_refreshed_at == a_week_ago
788
789 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
790
791 assert user.inbox
792
793 refute user.id == orig_user.id
794
795 orig_user = User.get_by_id(orig_user.id)
796
797 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
798 end
799
800 @tag capture_log: true
801 test "it returns the old user if stale, but unfetchable" do
802 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
803
804 orig_user =
805 insert(
806 :user,
807 local: false,
808 nickname: "admin@mastodon.example.org",
809 ap_id: "http://mastodon.example.org/users/raymoo",
810 last_refreshed_at: a_week_ago
811 )
812
813 assert orig_user.last_refreshed_at == a_week_ago
814
815 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
816
817 assert user.last_refreshed_at == orig_user.last_refreshed_at
818 end
819 end
820
821 test "returns an ap_id for a user" do
822 user = insert(:user)
823
824 assert User.ap_id(user) ==
825 Pleroma.Web.Router.Helpers.user_feed_url(
826 Pleroma.Web.Endpoint,
827 :feed_redirect,
828 user.nickname
829 )
830 end
831
832 test "returns an ap_followers link for a user" do
833 user = insert(:user)
834
835 assert User.ap_followers(user) ==
836 Pleroma.Web.Router.Helpers.user_feed_url(
837 Pleroma.Web.Endpoint,
838 :feed_redirect,
839 user.nickname
840 ) <> "/followers"
841 end
842
843 describe "remote user changeset" do
844 @valid_remote %{
845 bio: "hello",
846 name: "Someone",
847 nickname: "a@b.de",
848 ap_id: "http...",
849 avatar: %{some: "avatar"}
850 }
851 setup do: clear_config([:instance, :user_bio_length])
852 setup do: clear_config([:instance, :user_name_length])
853
854 test "it confirms validity" do
855 cs = User.remote_user_changeset(@valid_remote)
856 assert cs.valid?
857 end
858
859 test "it sets the follower_adress" do
860 cs = User.remote_user_changeset(@valid_remote)
861 # remote users get a fake local follower address
862 assert cs.changes.follower_address ==
863 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
864 end
865
866 test "it enforces the fqn format for nicknames" do
867 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
868 assert Ecto.Changeset.get_field(cs, :local) == false
869 assert cs.changes.avatar
870 refute cs.valid?
871 end
872
873 test "it has required fields" do
874 [:ap_id]
875 |> Enum.each(fn field ->
876 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
877 refute cs.valid?
878 end)
879 end
880 end
881
882 describe "followers and friends" do
883 test "gets all followers for a given user" do
884 user = insert(:user)
885 follower_one = insert(:user)
886 follower_two = insert(:user)
887 not_follower = insert(:user)
888
889 {:ok, follower_one} = User.follow(follower_one, user)
890 {:ok, follower_two} = User.follow(follower_two, user)
891
892 res = User.get_followers(user)
893
894 assert Enum.member?(res, follower_one)
895 assert Enum.member?(res, follower_two)
896 refute Enum.member?(res, not_follower)
897 end
898
899 test "gets all friends (followed users) for a given user" do
900 user = insert(:user)
901 followed_one = insert(:user)
902 followed_two = insert(:user)
903 not_followed = insert(:user)
904
905 {:ok, user} = User.follow(user, followed_one)
906 {:ok, user} = User.follow(user, followed_two)
907
908 res = User.get_friends(user)
909
910 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
911 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
912 assert Enum.member?(res, followed_one)
913 assert Enum.member?(res, followed_two)
914 refute Enum.member?(res, not_followed)
915 end
916 end
917
918 describe "updating note and follower count" do
919 test "it sets the note_count property" do
920 note = insert(:note)
921
922 user = User.get_cached_by_ap_id(note.data["actor"])
923
924 assert user.note_count == 0
925
926 {:ok, user} = User.update_note_count(user)
927
928 assert user.note_count == 1
929 end
930
931 test "it increases the note_count property" do
932 note = insert(:note)
933 user = User.get_cached_by_ap_id(note.data["actor"])
934
935 assert user.note_count == 0
936
937 {:ok, user} = User.increase_note_count(user)
938
939 assert user.note_count == 1
940
941 {:ok, user} = User.increase_note_count(user)
942
943 assert user.note_count == 2
944 end
945
946 test "it decreases the note_count property" do
947 note = insert(:note)
948 user = User.get_cached_by_ap_id(note.data["actor"])
949
950 assert user.note_count == 0
951
952 {:ok, user} = User.increase_note_count(user)
953
954 assert user.note_count == 1
955
956 {:ok, user} = User.decrease_note_count(user)
957
958 assert user.note_count == 0
959
960 {:ok, user} = User.decrease_note_count(user)
961
962 assert user.note_count == 0
963 end
964
965 test "it sets the follower_count property" do
966 user = insert(:user)
967 follower = insert(:user)
968
969 User.follow(follower, user)
970
971 assert user.follower_count == 0
972
973 {:ok, user} = User.update_follower_count(user)
974
975 assert user.follower_count == 1
976 end
977 end
978
979 describe "follow_import" do
980 test "it imports user followings from list" do
981 [user1, user2, user3] = insert_list(3, :user)
982
983 identifiers = [
984 user2.ap_id,
985 user3.nickname
986 ]
987
988 {:ok, job} = User.follow_import(user1, identifiers)
989
990 assert {:ok, result} = ObanHelpers.perform(job)
991 assert is_list(result)
992 assert result == [user2, user3]
993 end
994 end
995
996 describe "mutes" do
997 test "it mutes people" do
998 user = insert(:user)
999 muted_user = insert(:user)
1000
1001 refute User.mutes?(user, muted_user)
1002 refute User.muted_notifications?(user, muted_user)
1003
1004 {:ok, _user_relationships} = User.mute(user, muted_user)
1005
1006 assert User.mutes?(user, muted_user)
1007 assert User.muted_notifications?(user, muted_user)
1008 end
1009
1010 test "it unmutes users" do
1011 user = insert(:user)
1012 muted_user = insert(:user)
1013
1014 {:ok, _user_relationships} = User.mute(user, muted_user)
1015 {:ok, _user_mute} = User.unmute(user, muted_user)
1016
1017 refute User.mutes?(user, muted_user)
1018 refute User.muted_notifications?(user, muted_user)
1019 end
1020
1021 test "it mutes user without notifications" do
1022 user = insert(:user)
1023 muted_user = insert(:user)
1024
1025 refute User.mutes?(user, muted_user)
1026 refute User.muted_notifications?(user, muted_user)
1027
1028 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1029
1030 assert User.mutes?(user, muted_user)
1031 refute User.muted_notifications?(user, muted_user)
1032 end
1033 end
1034
1035 describe "blocks" do
1036 test "it blocks people" do
1037 user = insert(:user)
1038 blocked_user = insert(:user)
1039
1040 refute User.blocks?(user, blocked_user)
1041
1042 {:ok, _user_relationship} = User.block(user, blocked_user)
1043
1044 assert User.blocks?(user, blocked_user)
1045 end
1046
1047 test "it unblocks users" do
1048 user = insert(:user)
1049 blocked_user = insert(:user)
1050
1051 {:ok, _user_relationship} = User.block(user, blocked_user)
1052 {:ok, _user_block} = User.unblock(user, blocked_user)
1053
1054 refute User.blocks?(user, blocked_user)
1055 end
1056
1057 test "blocks tear down cyclical follow relationships" do
1058 blocker = insert(:user)
1059 blocked = insert(:user)
1060
1061 {:ok, blocker} = User.follow(blocker, blocked)
1062 {:ok, blocked} = User.follow(blocked, blocker)
1063
1064 assert User.following?(blocker, blocked)
1065 assert User.following?(blocked, blocker)
1066
1067 {:ok, _user_relationship} = User.block(blocker, blocked)
1068 blocked = User.get_cached_by_id(blocked.id)
1069
1070 assert User.blocks?(blocker, blocked)
1071
1072 refute User.following?(blocker, blocked)
1073 refute User.following?(blocked, blocker)
1074 end
1075
1076 test "blocks tear down blocker->blocked follow relationships" do
1077 blocker = insert(:user)
1078 blocked = insert(:user)
1079
1080 {:ok, blocker} = User.follow(blocker, blocked)
1081
1082 assert User.following?(blocker, blocked)
1083 refute User.following?(blocked, blocker)
1084
1085 {:ok, _user_relationship} = User.block(blocker, blocked)
1086 blocked = User.get_cached_by_id(blocked.id)
1087
1088 assert User.blocks?(blocker, blocked)
1089
1090 refute User.following?(blocker, blocked)
1091 refute User.following?(blocked, blocker)
1092 end
1093
1094 test "blocks tear down blocked->blocker follow relationships" do
1095 blocker = insert(:user)
1096 blocked = insert(:user)
1097
1098 {:ok, blocked} = User.follow(blocked, blocker)
1099
1100 refute User.following?(blocker, blocked)
1101 assert User.following?(blocked, blocker)
1102
1103 {:ok, _user_relationship} = User.block(blocker, blocked)
1104 blocked = User.get_cached_by_id(blocked.id)
1105
1106 assert User.blocks?(blocker, blocked)
1107
1108 refute User.following?(blocker, blocked)
1109 refute User.following?(blocked, blocker)
1110 end
1111
1112 test "blocks tear down blocked->blocker subscription relationships" do
1113 blocker = insert(:user)
1114 blocked = insert(:user)
1115
1116 {:ok, _subscription} = User.subscribe(blocked, blocker)
1117
1118 assert User.subscribed_to?(blocked, blocker)
1119 refute User.subscribed_to?(blocker, blocked)
1120
1121 {:ok, _user_relationship} = User.block(blocker, blocked)
1122
1123 assert User.blocks?(blocker, blocked)
1124 refute User.subscribed_to?(blocker, blocked)
1125 refute User.subscribed_to?(blocked, blocker)
1126 end
1127 end
1128
1129 describe "domain blocking" do
1130 test "blocks domains" do
1131 user = insert(:user)
1132 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1133
1134 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1135
1136 assert User.blocks?(user, collateral_user)
1137 end
1138
1139 test "does not block domain with same end" do
1140 user = insert(:user)
1141
1142 collateral_user =
1143 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1144
1145 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1146
1147 refute User.blocks?(user, collateral_user)
1148 end
1149
1150 test "does not block domain with same end if wildcard added" do
1151 user = insert(:user)
1152
1153 collateral_user =
1154 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1155
1156 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1157
1158 refute User.blocks?(user, collateral_user)
1159 end
1160
1161 test "blocks domain with wildcard for subdomain" do
1162 user = insert(:user)
1163
1164 user_from_subdomain =
1165 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1166
1167 user_with_two_subdomains =
1168 insert(:user, %{
1169 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1170 })
1171
1172 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1173
1174 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1175
1176 assert User.blocks?(user, user_from_subdomain)
1177 assert User.blocks?(user, user_with_two_subdomains)
1178 assert User.blocks?(user, user_domain)
1179 end
1180
1181 test "unblocks domains" do
1182 user = insert(:user)
1183 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1184
1185 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1186 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1187
1188 refute User.blocks?(user, collateral_user)
1189 end
1190
1191 test "follows take precedence over domain blocks" do
1192 user = insert(:user)
1193 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1194
1195 {:ok, user} = User.block_domain(user, "meanies.social")
1196 {:ok, user} = User.follow(user, good_eggo)
1197
1198 refute User.blocks?(user, good_eggo)
1199 end
1200 end
1201
1202 describe "blocks_import" do
1203 test "it imports user blocks from list" do
1204 [user1, user2, user3] = insert_list(3, :user)
1205
1206 identifiers = [
1207 user2.ap_id,
1208 user3.nickname
1209 ]
1210
1211 {:ok, job} = User.blocks_import(user1, identifiers)
1212
1213 assert {:ok, result} = ObanHelpers.perform(job)
1214 assert is_list(result)
1215 assert result == [user2, user3]
1216 end
1217 end
1218
1219 describe "get_recipients_from_activity" do
1220 test "works for announces" do
1221 actor = insert(:user)
1222 user = insert(:user, local: true)
1223
1224 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1225 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1226
1227 recipients = User.get_recipients_from_activity(announce)
1228
1229 assert user in recipients
1230 end
1231
1232 test "get recipients" do
1233 actor = insert(:user)
1234 user = insert(:user, local: true)
1235 user_two = insert(:user, local: false)
1236 addressed = insert(:user, local: true)
1237 addressed_remote = insert(:user, local: false)
1238
1239 {:ok, activity} =
1240 CommonAPI.post(actor, %{
1241 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1242 })
1243
1244 assert Enum.map([actor, addressed], & &1.ap_id) --
1245 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1246
1247 {:ok, user} = User.follow(user, actor)
1248 {:ok, _user_two} = User.follow(user_two, actor)
1249 recipients = User.get_recipients_from_activity(activity)
1250 assert length(recipients) == 3
1251 assert user in recipients
1252 assert addressed in recipients
1253 end
1254
1255 test "has following" do
1256 actor = insert(:user)
1257 user = insert(:user)
1258 user_two = insert(:user)
1259 addressed = insert(:user, local: true)
1260
1261 {:ok, activity} =
1262 CommonAPI.post(actor, %{
1263 status: "hey @#{addressed.nickname}"
1264 })
1265
1266 assert Enum.map([actor, addressed], & &1.ap_id) --
1267 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1268
1269 {:ok, _actor} = User.follow(actor, user)
1270 {:ok, _actor} = User.follow(actor, user_two)
1271 recipients = User.get_recipients_from_activity(activity)
1272 assert length(recipients) == 2
1273 assert addressed in recipients
1274 end
1275 end
1276
1277 describe ".deactivate" do
1278 test "can de-activate then re-activate a user" do
1279 user = insert(:user)
1280 assert false == user.deactivated
1281 {:ok, user} = User.deactivate(user)
1282 assert true == user.deactivated
1283 {:ok, user} = User.deactivate(user, false)
1284 assert false == user.deactivated
1285 end
1286
1287 test "hide a user from followers" do
1288 user = insert(:user)
1289 user2 = insert(:user)
1290
1291 {:ok, user} = User.follow(user, user2)
1292 {:ok, _user} = User.deactivate(user)
1293
1294 user2 = User.get_cached_by_id(user2.id)
1295
1296 assert user2.follower_count == 0
1297 assert [] = User.get_followers(user2)
1298 end
1299
1300 test "hide a user from friends" do
1301 user = insert(:user)
1302 user2 = insert(:user)
1303
1304 {:ok, user2} = User.follow(user2, user)
1305 assert user2.following_count == 1
1306 assert User.following_count(user2) == 1
1307
1308 {:ok, _user} = User.deactivate(user)
1309
1310 user2 = User.get_cached_by_id(user2.id)
1311
1312 assert refresh_record(user2).following_count == 0
1313 assert user2.following_count == 0
1314 assert User.following_count(user2) == 0
1315 assert [] = User.get_friends(user2)
1316 end
1317
1318 test "hide a user's statuses from timelines and notifications" do
1319 user = insert(:user)
1320 user2 = insert(:user)
1321
1322 {:ok, user2} = User.follow(user2, user)
1323
1324 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1325
1326 activity = Repo.preload(activity, :bookmark)
1327
1328 [notification] = Pleroma.Notification.for_user(user2)
1329 assert notification.activity.id == activity.id
1330
1331 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1332
1333 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1334 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1335 user: user2
1336 })
1337
1338 {:ok, _user} = User.deactivate(user)
1339
1340 assert [] == ActivityPub.fetch_public_activities(%{})
1341 assert [] == Pleroma.Notification.for_user(user2)
1342
1343 assert [] ==
1344 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1345 user: user2
1346 })
1347 end
1348 end
1349
1350 describe "approve" do
1351 test "approves a user" do
1352 user = insert(:user, approval_pending: true)
1353 assert true == user.approval_pending
1354 {:ok, user} = User.approve(user)
1355 assert false == user.approval_pending
1356 end
1357
1358 test "approves a list of users" do
1359 unapproved_users = [
1360 insert(:user, approval_pending: true),
1361 insert(:user, approval_pending: true),
1362 insert(:user, approval_pending: true)
1363 ]
1364
1365 {:ok, users} = User.approve(unapproved_users)
1366
1367 assert Enum.count(users) == 3
1368
1369 Enum.each(users, fn user ->
1370 assert false == user.approval_pending
1371 end)
1372 end
1373 end
1374
1375 describe "delete" do
1376 setup do
1377 {:ok, user} = insert(:user) |> User.set_cache()
1378
1379 [user: user]
1380 end
1381
1382 setup do: clear_config([:instance, :federating])
1383
1384 test ".delete_user_activities deletes all create activities", %{user: user} do
1385 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1386
1387 User.delete_user_activities(user)
1388
1389 # TODO: Test removal favorites, repeats, delete activities.
1390 refute Activity.get_by_id(activity.id)
1391 end
1392
1393 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1394 follower = insert(:user)
1395 {:ok, follower} = User.follow(follower, user)
1396
1397 locked_user = insert(:user, name: "locked", locked: true)
1398 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1399
1400 object = insert(:note, user: user)
1401 activity = insert(:note_activity, user: user, note: object)
1402
1403 object_two = insert(:note, user: follower)
1404 activity_two = insert(:note_activity, user: follower, note: object_two)
1405
1406 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1407 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1408 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1409
1410 {:ok, job} = User.delete(user)
1411 {:ok, _user} = ObanHelpers.perform(job)
1412
1413 follower = User.get_cached_by_id(follower.id)
1414
1415 refute User.following?(follower, user)
1416 assert %{deactivated: true} = User.get_by_id(user.id)
1417
1418 assert [] == User.get_follow_requests(locked_user)
1419
1420 user_activities =
1421 user.ap_id
1422 |> Activity.Queries.by_actor()
1423 |> Repo.all()
1424 |> Enum.map(fn act -> act.data["type"] end)
1425
1426 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1427
1428 refute Activity.get_by_id(activity.id)
1429 refute Activity.get_by_id(like.id)
1430 refute Activity.get_by_id(like_two.id)
1431 refute Activity.get_by_id(repeat.id)
1432 end
1433 end
1434
1435 describe "delete/1 when confirmation is pending" do
1436 setup do
1437 user = insert(:user, confirmation_pending: true)
1438 {:ok, user: user}
1439 end
1440
1441 test "deletes user from database when activation required", %{user: user} do
1442 clear_config([:instance, :account_activation_required], true)
1443
1444 {:ok, job} = User.delete(user)
1445 {:ok, _} = ObanHelpers.perform(job)
1446
1447 refute User.get_cached_by_id(user.id)
1448 refute User.get_by_id(user.id)
1449 end
1450
1451 test "deactivates user when activation is not required", %{user: user} do
1452 clear_config([:instance, :account_activation_required], false)
1453
1454 {:ok, job} = User.delete(user)
1455 {:ok, _} = ObanHelpers.perform(job)
1456
1457 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1458 assert %{deactivated: true} = User.get_by_id(user.id)
1459 end
1460 end
1461
1462 test "delete/1 when approval is pending deletes the user" do
1463 user = insert(:user, approval_pending: true)
1464
1465 {:ok, job} = User.delete(user)
1466 {:ok, _} = ObanHelpers.perform(job)
1467
1468 refute User.get_cached_by_id(user.id)
1469 refute User.get_by_id(user.id)
1470 end
1471
1472 test "delete/1 purges a user when they wouldn't be fully deleted" do
1473 user =
1474 insert(:user, %{
1475 bio: "eyy lmao",
1476 name: "qqqqqqq",
1477 password_hash: "pdfk2$1b3n159001",
1478 keys: "RSA begin buplic key",
1479 public_key: "--PRIVATE KEYE--",
1480 avatar: %{"a" => "b"},
1481 tags: ["qqqqq"],
1482 banner: %{"a" => "b"},
1483 background: %{"a" => "b"},
1484 note_count: 9,
1485 follower_count: 9,
1486 following_count: 9001,
1487 locked: true,
1488 confirmation_pending: true,
1489 password_reset_pending: true,
1490 approval_pending: true,
1491 registration_reason: "ahhhhh",
1492 confirmation_token: "qqqq",
1493 domain_blocks: ["lain.com"],
1494 deactivated: true,
1495 ap_enabled: true,
1496 is_moderator: true,
1497 is_admin: true,
1498 mastofe_settings: %{"a" => "b"},
1499 mascot: %{"a" => "b"},
1500 emoji: %{"a" => "b"},
1501 pleroma_settings_store: %{"q" => "x"},
1502 fields: [%{"gg" => "qq"}],
1503 raw_fields: [%{"gg" => "qq"}],
1504 discoverable: true,
1505 also_known_as: ["https://lol.olo/users/loll"]
1506 })
1507
1508 {:ok, job} = User.delete(user)
1509 {:ok, _} = ObanHelpers.perform(job)
1510 user = User.get_by_id(user.id)
1511
1512 assert %User{
1513 bio: nil,
1514 raw_bio: nil,
1515 email: nil,
1516 name: nil,
1517 password_hash: nil,
1518 keys: nil,
1519 public_key: nil,
1520 avatar: %{},
1521 tags: [],
1522 last_refreshed_at: nil,
1523 last_digest_emailed_at: nil,
1524 banner: %{},
1525 background: %{},
1526 note_count: 0,
1527 follower_count: 0,
1528 following_count: 0,
1529 locked: false,
1530 confirmation_pending: false,
1531 password_reset_pending: false,
1532 approval_pending: false,
1533 registration_reason: nil,
1534 confirmation_token: nil,
1535 domain_blocks: [],
1536 deactivated: true,
1537 ap_enabled: false,
1538 is_moderator: false,
1539 is_admin: false,
1540 mastofe_settings: nil,
1541 mascot: nil,
1542 emoji: %{},
1543 pleroma_settings_store: %{},
1544 fields: [],
1545 raw_fields: [],
1546 discoverable: false,
1547 also_known_as: []
1548 } = user
1549 end
1550
1551 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1552 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1553 end
1554
1555 describe "per-user rich-text filtering" do
1556 test "html_filter_policy returns default policies, when rich-text is enabled" do
1557 user = insert(:user)
1558
1559 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1560 end
1561
1562 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1563 user = insert(:user, no_rich_text: true)
1564
1565 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1566 end
1567 end
1568
1569 describe "caching" do
1570 test "invalidate_cache works" do
1571 user = insert(:user)
1572
1573 User.set_cache(user)
1574 User.invalidate_cache(user)
1575
1576 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1577 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1578 end
1579
1580 test "User.delete() plugs any possible zombie objects" do
1581 user = insert(:user)
1582
1583 {:ok, job} = User.delete(user)
1584 {:ok, _} = ObanHelpers.perform(job)
1585
1586 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1587
1588 assert cached_user != user
1589
1590 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1591
1592 assert cached_user != user
1593 end
1594 end
1595
1596 describe "account_status/1" do
1597 setup do: clear_config([:instance, :account_activation_required])
1598
1599 test "return confirmation_pending for unconfirm user" do
1600 Pleroma.Config.put([:instance, :account_activation_required], true)
1601 user = insert(:user, confirmation_pending: true)
1602 assert User.account_status(user) == :confirmation_pending
1603 end
1604
1605 test "return active for confirmed user" do
1606 Pleroma.Config.put([:instance, :account_activation_required], true)
1607 user = insert(:user, confirmation_pending: false)
1608 assert User.account_status(user) == :active
1609 end
1610
1611 test "return active for remote user" do
1612 user = insert(:user, local: false)
1613 assert User.account_status(user) == :active
1614 end
1615
1616 test "returns :password_reset_pending for user with reset password" do
1617 user = insert(:user, password_reset_pending: true)
1618 assert User.account_status(user) == :password_reset_pending
1619 end
1620
1621 test "returns :deactivated for deactivated user" do
1622 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1623 assert User.account_status(user) == :deactivated
1624 end
1625
1626 test "returns :approval_pending for unapproved user" do
1627 user = insert(:user, local: true, approval_pending: true)
1628 assert User.account_status(user) == :approval_pending
1629
1630 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1631 assert User.account_status(user) == :approval_pending
1632 end
1633 end
1634
1635 describe "superuser?/1" do
1636 test "returns false for unprivileged users" do
1637 user = insert(:user, local: true)
1638
1639 refute User.superuser?(user)
1640 end
1641
1642 test "returns false for remote users" do
1643 user = insert(:user, local: false)
1644 remote_admin_user = insert(:user, local: false, is_admin: true)
1645
1646 refute User.superuser?(user)
1647 refute User.superuser?(remote_admin_user)
1648 end
1649
1650 test "returns true for local moderators" do
1651 user = insert(:user, local: true, is_moderator: true)
1652
1653 assert User.superuser?(user)
1654 end
1655
1656 test "returns true for local admins" do
1657 user = insert(:user, local: true, is_admin: true)
1658
1659 assert User.superuser?(user)
1660 end
1661 end
1662
1663 describe "invisible?/1" do
1664 test "returns true for an invisible user" do
1665 user = insert(:user, local: true, invisible: true)
1666
1667 assert User.invisible?(user)
1668 end
1669
1670 test "returns false for a non-invisible user" do
1671 user = insert(:user, local: true)
1672
1673 refute User.invisible?(user)
1674 end
1675 end
1676
1677 describe "visible_for/2" do
1678 test "returns true when the account is itself" do
1679 user = insert(:user, local: true)
1680
1681 assert User.visible_for(user, user) == :visible
1682 end
1683
1684 test "returns false when the account is unauthenticated and auth is required" do
1685 Pleroma.Config.put([:instance, :account_activation_required], true)
1686
1687 user = insert(:user, local: true, confirmation_pending: true)
1688 other_user = insert(:user, local: true)
1689
1690 refute User.visible_for(user, other_user) == :visible
1691 end
1692
1693 test "returns true when the account is unauthenticated and auth is not required" do
1694 user = insert(:user, local: true, confirmation_pending: true)
1695 other_user = insert(:user, local: true)
1696
1697 assert User.visible_for(user, other_user) == :visible
1698 end
1699
1700 test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
1701 Pleroma.Config.put([:instance, :account_activation_required], true)
1702
1703 user = insert(:user, local: true, confirmation_pending: true)
1704 other_user = insert(:user, local: true, is_admin: true)
1705
1706 assert User.visible_for(user, other_user) == :visible
1707 end
1708 end
1709
1710 describe "parse_bio/2" do
1711 test "preserves hosts in user links text" do
1712 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1713 user = insert(:user)
1714 bio = "A.k.a. @nick@domain.com"
1715
1716 expected_text =
1717 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1718 remote_user.ap_id
1719 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1720
1721 assert expected_text == User.parse_bio(bio, user)
1722 end
1723
1724 test "Adds rel=me on linkbacked urls" do
1725 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1726
1727 bio = "http://example.com/rel_me/null"
1728 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1729 assert expected_text == User.parse_bio(bio, user)
1730
1731 bio = "http://example.com/rel_me/link"
1732 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1733 assert expected_text == User.parse_bio(bio, user)
1734
1735 bio = "http://example.com/rel_me/anchor"
1736 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1737 assert expected_text == User.parse_bio(bio, user)
1738 end
1739 end
1740
1741 test "follower count is updated when a follower is blocked" do
1742 user = insert(:user)
1743 follower = insert(:user)
1744 follower2 = insert(:user)
1745 follower3 = insert(:user)
1746
1747 {:ok, follower} = User.follow(follower, user)
1748 {:ok, _follower2} = User.follow(follower2, user)
1749 {:ok, _follower3} = User.follow(follower3, user)
1750
1751 {:ok, _user_relationship} = User.block(user, follower)
1752 user = refresh_record(user)
1753
1754 assert user.follower_count == 2
1755 end
1756
1757 describe "list_inactive_users_query/1" do
1758 defp days_ago(days) do
1759 NaiveDateTime.add(
1760 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1761 -days * 60 * 60 * 24,
1762 :second
1763 )
1764 end
1765
1766 test "Users are inactive by default" do
1767 total = 10
1768
1769 users =
1770 Enum.map(1..total, fn _ ->
1771 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1772 end)
1773
1774 inactive_users_ids =
1775 Pleroma.User.list_inactive_users_query()
1776 |> Pleroma.Repo.all()
1777 |> Enum.map(& &1.id)
1778
1779 Enum.each(users, fn user ->
1780 assert user.id in inactive_users_ids
1781 end)
1782 end
1783
1784 test "Only includes users who has no recent activity" do
1785 total = 10
1786
1787 users =
1788 Enum.map(1..total, fn _ ->
1789 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1790 end)
1791
1792 {inactive, active} = Enum.split(users, trunc(total / 2))
1793
1794 Enum.map(active, fn user ->
1795 to = Enum.random(users -- [user])
1796
1797 {:ok, _} =
1798 CommonAPI.post(user, %{
1799 status: "hey @#{to.nickname}"
1800 })
1801 end)
1802
1803 inactive_users_ids =
1804 Pleroma.User.list_inactive_users_query()
1805 |> Pleroma.Repo.all()
1806 |> Enum.map(& &1.id)
1807
1808 Enum.each(active, fn user ->
1809 refute user.id in inactive_users_ids
1810 end)
1811
1812 Enum.each(inactive, fn user ->
1813 assert user.id in inactive_users_ids
1814 end)
1815 end
1816
1817 test "Only includes users with no read notifications" do
1818 total = 10
1819
1820 users =
1821 Enum.map(1..total, fn _ ->
1822 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1823 end)
1824
1825 [sender | recipients] = users
1826 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1827
1828 Enum.each(recipients, fn to ->
1829 {:ok, _} =
1830 CommonAPI.post(sender, %{
1831 status: "hey @#{to.nickname}"
1832 })
1833
1834 {:ok, _} =
1835 CommonAPI.post(sender, %{
1836 status: "hey again @#{to.nickname}"
1837 })
1838 end)
1839
1840 Enum.each(active, fn user ->
1841 [n1, _n2] = Pleroma.Notification.for_user(user)
1842 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1843 end)
1844
1845 inactive_users_ids =
1846 Pleroma.User.list_inactive_users_query()
1847 |> Pleroma.Repo.all()
1848 |> Enum.map(& &1.id)
1849
1850 Enum.each(active, fn user ->
1851 refute user.id in inactive_users_ids
1852 end)
1853
1854 Enum.each(inactive, fn user ->
1855 assert user.id in inactive_users_ids
1856 end)
1857 end
1858 end
1859
1860 describe "toggle_confirmation/1" do
1861 test "if user is confirmed" do
1862 user = insert(:user, confirmation_pending: false)
1863 {:ok, user} = User.toggle_confirmation(user)
1864
1865 assert user.confirmation_pending
1866 assert user.confirmation_token
1867 end
1868
1869 test "if user is unconfirmed" do
1870 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1871 {:ok, user} = User.toggle_confirmation(user)
1872
1873 refute user.confirmation_pending
1874 refute user.confirmation_token
1875 end
1876 end
1877
1878 describe "ensure_keys_present" do
1879 test "it creates keys for a user and stores them in info" do
1880 user = insert(:user)
1881 refute is_binary(user.keys)
1882 {:ok, user} = User.ensure_keys_present(user)
1883 assert is_binary(user.keys)
1884 end
1885
1886 test "it doesn't create keys if there already are some" do
1887 user = insert(:user, keys: "xxx")
1888 {:ok, user} = User.ensure_keys_present(user)
1889 assert user.keys == "xxx"
1890 end
1891 end
1892
1893 describe "get_ap_ids_by_nicknames" do
1894 test "it returns a list of AP ids for a given set of nicknames" do
1895 user = insert(:user)
1896 user_two = insert(:user)
1897
1898 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1899 assert length(ap_ids) == 2
1900 assert user.ap_id in ap_ids
1901 assert user_two.ap_id in ap_ids
1902 end
1903 end
1904
1905 describe "sync followers count" do
1906 setup do
1907 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1908 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1909 insert(:user, local: true)
1910 insert(:user, local: false, deactivated: true)
1911 {:ok, user1: user1, user2: user2}
1912 end
1913
1914 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1915 [fdb_user1] = User.external_users(limit: 1)
1916
1917 assert fdb_user1.ap_id
1918 assert fdb_user1.ap_id == user1.ap_id
1919 assert fdb_user1.id == user1.id
1920
1921 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1922
1923 assert fdb_user2.ap_id
1924 assert fdb_user2.ap_id == user2.ap_id
1925 assert fdb_user2.id == user2.id
1926
1927 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1928 end
1929 end
1930
1931 describe "is_internal_user?/1" do
1932 test "non-internal user returns false" do
1933 user = insert(:user)
1934 refute User.is_internal_user?(user)
1935 end
1936
1937 test "user with no nickname returns true" do
1938 user = insert(:user, %{nickname: nil})
1939 assert User.is_internal_user?(user)
1940 end
1941
1942 test "user with internal-prefixed nickname returns true" do
1943 user = insert(:user, %{nickname: "internal.test"})
1944 assert User.is_internal_user?(user)
1945 end
1946 end
1947
1948 describe "update_and_set_cache/1" do
1949 test "returns error when user is stale instead Ecto.StaleEntryError" do
1950 user = insert(:user)
1951
1952 changeset = Ecto.Changeset.change(user, bio: "test")
1953
1954 Repo.delete(user)
1955
1956 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1957 User.update_and_set_cache(changeset)
1958 end
1959
1960 test "performs update cache if user updated" do
1961 user = insert(:user)
1962 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1963
1964 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1965
1966 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1967 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1968 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1969 end
1970 end
1971
1972 describe "following/followers synchronization" do
1973 setup do: clear_config([:instance, :external_user_synchronization])
1974
1975 test "updates the counters normally on following/getting a follow when disabled" do
1976 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1977 user = insert(:user)
1978
1979 other_user =
1980 insert(:user,
1981 local: false,
1982 follower_address: "http://localhost:4001/users/masto_closed/followers",
1983 following_address: "http://localhost:4001/users/masto_closed/following",
1984 ap_enabled: true
1985 )
1986
1987 assert other_user.following_count == 0
1988 assert other_user.follower_count == 0
1989
1990 {:ok, user} = Pleroma.User.follow(user, other_user)
1991 other_user = Pleroma.User.get_by_id(other_user.id)
1992
1993 assert user.following_count == 1
1994 assert other_user.follower_count == 1
1995 end
1996
1997 test "syncronizes the counters with the remote instance for the followed when enabled" do
1998 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1999
2000 user = insert(:user)
2001
2002 other_user =
2003 insert(:user,
2004 local: false,
2005 follower_address: "http://localhost:4001/users/masto_closed/followers",
2006 following_address: "http://localhost:4001/users/masto_closed/following",
2007 ap_enabled: true
2008 )
2009
2010 assert other_user.following_count == 0
2011 assert other_user.follower_count == 0
2012
2013 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2014 {:ok, _user} = User.follow(user, other_user)
2015 other_user = User.get_by_id(other_user.id)
2016
2017 assert other_user.follower_count == 437
2018 end
2019
2020 test "syncronizes the counters with the remote instance for the follower when enabled" do
2021 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2022
2023 user = insert(:user)
2024
2025 other_user =
2026 insert(:user,
2027 local: false,
2028 follower_address: "http://localhost:4001/users/masto_closed/followers",
2029 following_address: "http://localhost:4001/users/masto_closed/following",
2030 ap_enabled: true
2031 )
2032
2033 assert other_user.following_count == 0
2034 assert other_user.follower_count == 0
2035
2036 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2037 {:ok, other_user} = User.follow(other_user, user)
2038
2039 assert other_user.following_count == 152
2040 end
2041 end
2042
2043 describe "change_email/2" do
2044 setup do
2045 [user: insert(:user)]
2046 end
2047
2048 test "blank email returns error", %{user: user} do
2049 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2050 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2051 end
2052
2053 test "non unique email returns error", %{user: user} do
2054 %{email: email} = insert(:user)
2055
2056 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2057 User.change_email(user, email)
2058 end
2059
2060 test "invalid email returns error", %{user: user} do
2061 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2062 User.change_email(user, "cofe")
2063 end
2064
2065 test "changes email", %{user: user} do
2066 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2067 end
2068 end
2069
2070 describe "get_cached_by_nickname_or_id" do
2071 setup do
2072 local_user = insert(:user)
2073 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2074
2075 [local_user: local_user, remote_user: remote_user]
2076 end
2077
2078 setup do: clear_config([:instance, :limit_to_local_content])
2079
2080 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2081 remote_user: remote_user
2082 } do
2083 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2084 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2085
2086 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2087 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2088
2089 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2090 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2091 end
2092
2093 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2094 %{remote_user: remote_user} do
2095 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2096 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2097 end
2098
2099 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2100 %{remote_user: remote_user, local_user: local_user} do
2101 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2102 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2103 end
2104
2105 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2106 %{remote_user: remote_user} do
2107 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2108 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2109 end
2110
2111 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2112 %{local_user: local_user} do
2113 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2114 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2115
2116 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2117 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2118
2119 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2120 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2121 end
2122 end
2123
2124 describe "update_email_notifications/2" do
2125 setup do
2126 user = insert(:user, email_notifications: %{"digest" => true})
2127
2128 {:ok, user: user}
2129 end
2130
2131 test "Notifications are updated", %{user: user} do
2132 true = user.email_notifications["digest"]
2133 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2134 assert result.email_notifications["digest"] == false
2135 end
2136 end
2137
2138 test "avatar fallback" do
2139 user = insert(:user)
2140 assert User.avatar_url(user) =~ "/images/avi.png"
2141
2142 clear_config([:assets, :default_user_avatar], "avatar.png")
2143
2144 user = User.get_cached_by_nickname_or_id(user.nickname)
2145 assert User.avatar_url(user) =~ "avatar.png"
2146
2147 assert User.avatar_url(user, no_default: true) == nil
2148 end
2149 end