Registration tests
[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 "sends a pending approval email" do
521 clear_config([:instance, :account_approval_required], true)
522
523 {:ok, user} =
524 User.register_changeset(%User{}, @full_user_data)
525 |> User.register()
526
527 ObanHelpers.perform_all()
528
529 assert_email_sent(
530 from: Pleroma.Config.Helpers.sender(),
531 to: {user.name, user.email},
532 subject: "Your account is awaiting approval"
533 )
534 end
535
536 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
537 Pleroma.Config.put([:instance, :account_activation_required], true)
538
539 @full_user_data
540 |> Map.keys()
541 |> Enum.each(fn key ->
542 params = Map.delete(@full_user_data, key)
543 changeset = User.register_changeset(%User{}, params)
544
545 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
546 end)
547 end
548
549 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
550 Pleroma.Config.put([:instance, :account_activation_required], false)
551
552 @full_user_data
553 |> Map.keys()
554 |> Enum.each(fn key ->
555 params = Map.delete(@full_user_data, key)
556 changeset = User.register_changeset(%User{}, params)
557
558 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
559 end)
560 end
561
562 test "it restricts certain nicknames" do
563 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
564
565 assert is_bitstring(restricted_name)
566
567 params =
568 @full_user_data
569 |> Map.put(:nickname, restricted_name)
570
571 changeset = User.register_changeset(%User{}, params)
572
573 refute changeset.valid?
574 end
575
576 test "it blocks blacklisted email domains" do
577 clear_config([User, :email_blacklist], ["trolling.world"])
578
579 # Block with match
580 params = Map.put(@full_user_data, :email, "troll@trolling.world")
581 changeset = User.register_changeset(%User{}, params)
582 refute changeset.valid?
583
584 # Block with subdomain match
585 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
586 changeset = User.register_changeset(%User{}, params)
587 refute changeset.valid?
588
589 # Pass with different domains that are similar
590 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
591 changeset = User.register_changeset(%User{}, params)
592 assert changeset.valid?
593
594 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
595 changeset = User.register_changeset(%User{}, params)
596 assert changeset.valid?
597 end
598
599 test "it sets the password_hash and ap_id" do
600 changeset = User.register_changeset(%User{}, @full_user_data)
601
602 assert changeset.valid?
603
604 assert is_binary(changeset.changes[:password_hash])
605 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
606
607 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
608 end
609
610 test "it sets the 'accepts_chat_messages' set to true" do
611 changeset = User.register_changeset(%User{}, @full_user_data)
612 assert changeset.valid?
613
614 {:ok, user} = Repo.insert(changeset)
615
616 assert user.accepts_chat_messages
617 end
618
619 test "it creates a confirmed user" do
620 changeset = User.register_changeset(%User{}, @full_user_data)
621 assert changeset.valid?
622
623 {:ok, user} = Repo.insert(changeset)
624
625 refute user.confirmation_pending
626 end
627 end
628
629 describe "user registration, with :account_activation_required" do
630 @full_user_data %{
631 bio: "A guy",
632 name: "my name",
633 nickname: "nick",
634 password: "test",
635 password_confirmation: "test",
636 email: "email@example.com"
637 }
638 setup do: clear_config([:instance, :account_activation_required], true)
639
640 test "it creates unconfirmed user" do
641 changeset = User.register_changeset(%User{}, @full_user_data)
642 assert changeset.valid?
643
644 {:ok, user} = Repo.insert(changeset)
645
646 assert user.confirmation_pending
647 assert user.confirmation_token
648 end
649
650 test "it creates confirmed user if :confirmed option is given" do
651 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
652 assert changeset.valid?
653
654 {:ok, user} = Repo.insert(changeset)
655
656 refute user.confirmation_pending
657 refute user.confirmation_token
658 end
659 end
660
661 describe "user registration, with :account_approval_required" do
662 @full_user_data %{
663 bio: "A guy",
664 name: "my name",
665 nickname: "nick",
666 password: "test",
667 password_confirmation: "test",
668 email: "email@example.com",
669 registration_reason: "I'm a cool guy :)"
670 }
671 setup do: clear_config([:instance, :account_approval_required], true)
672
673 test "it creates unapproved user" do
674 changeset = User.register_changeset(%User{}, @full_user_data)
675 assert changeset.valid?
676
677 {:ok, user} = Repo.insert(changeset)
678
679 assert user.approval_pending
680 assert user.registration_reason == "I'm a cool guy :)"
681 end
682
683 test "it restricts length of registration reason" do
684 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
685
686 assert is_integer(reason_limit)
687
688 params =
689 @full_user_data
690 |> Map.put(
691 :registration_reason,
692 "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."
693 )
694
695 changeset = User.register_changeset(%User{}, params)
696
697 refute changeset.valid?
698 end
699 end
700
701 describe "get_or_fetch/1" do
702 test "gets an existing user by nickname" do
703 user = insert(:user)
704 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
705
706 assert user == fetched_user
707 end
708
709 test "gets an existing user by ap_id" do
710 ap_id = "http://mastodon.example.org/users/admin"
711
712 user =
713 insert(
714 :user,
715 local: false,
716 nickname: "admin@mastodon.example.org",
717 ap_id: ap_id
718 )
719
720 {:ok, fetched_user} = User.get_or_fetch(ap_id)
721 freshed_user = refresh_record(user)
722 assert freshed_user == fetched_user
723 end
724 end
725
726 describe "fetching a user from nickname or trying to build one" do
727 test "gets an existing user" do
728 user = insert(:user)
729 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
730
731 assert user == fetched_user
732 end
733
734 test "gets an existing user, case insensitive" do
735 user = insert(:user, nickname: "nick")
736 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
737
738 assert user == fetched_user
739 end
740
741 test "gets an existing user by fully qualified nickname" do
742 user = insert(:user)
743
744 {:ok, fetched_user} =
745 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
746
747 assert user == fetched_user
748 end
749
750 test "gets an existing user by fully qualified nickname, case insensitive" do
751 user = insert(:user, nickname: "nick")
752 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
753
754 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
755
756 assert user == fetched_user
757 end
758
759 @tag capture_log: true
760 test "returns nil if no user could be fetched" do
761 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
762 assert fetched_user == "not found nonexistant@social.heldscal.la"
763 end
764
765 test "returns nil for nonexistant local user" do
766 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
767 assert fetched_user == "not found nonexistant"
768 end
769
770 test "updates an existing user, if stale" do
771 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
772
773 orig_user =
774 insert(
775 :user,
776 local: false,
777 nickname: "admin@mastodon.example.org",
778 ap_id: "http://mastodon.example.org/users/admin",
779 last_refreshed_at: a_week_ago
780 )
781
782 assert orig_user.last_refreshed_at == a_week_ago
783
784 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
785
786 assert user.inbox
787
788 refute user.last_refreshed_at == orig_user.last_refreshed_at
789 end
790
791 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
792 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
793
794 orig_user =
795 insert(
796 :user,
797 local: false,
798 nickname: "admin@mastodon.example.org",
799 ap_id: "http://mastodon.example.org/users/harinezumigari",
800 last_refreshed_at: a_week_ago
801 )
802
803 assert orig_user.last_refreshed_at == a_week_ago
804
805 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
806
807 assert user.inbox
808
809 refute user.id == orig_user.id
810
811 orig_user = User.get_by_id(orig_user.id)
812
813 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
814 end
815
816 @tag capture_log: true
817 test "it returns the old user if stale, but unfetchable" do
818 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
819
820 orig_user =
821 insert(
822 :user,
823 local: false,
824 nickname: "admin@mastodon.example.org",
825 ap_id: "http://mastodon.example.org/users/raymoo",
826 last_refreshed_at: a_week_ago
827 )
828
829 assert orig_user.last_refreshed_at == a_week_ago
830
831 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
832
833 assert user.last_refreshed_at == orig_user.last_refreshed_at
834 end
835 end
836
837 test "returns an ap_id for a user" do
838 user = insert(:user)
839
840 assert User.ap_id(user) ==
841 Pleroma.Web.Router.Helpers.user_feed_url(
842 Pleroma.Web.Endpoint,
843 :feed_redirect,
844 user.nickname
845 )
846 end
847
848 test "returns an ap_followers link for a user" do
849 user = insert(:user)
850
851 assert User.ap_followers(user) ==
852 Pleroma.Web.Router.Helpers.user_feed_url(
853 Pleroma.Web.Endpoint,
854 :feed_redirect,
855 user.nickname
856 ) <> "/followers"
857 end
858
859 describe "remote user changeset" do
860 @valid_remote %{
861 bio: "hello",
862 name: "Someone",
863 nickname: "a@b.de",
864 ap_id: "http...",
865 avatar: %{some: "avatar"}
866 }
867 setup do: clear_config([:instance, :user_bio_length])
868 setup do: clear_config([:instance, :user_name_length])
869
870 test "it confirms validity" do
871 cs = User.remote_user_changeset(@valid_remote)
872 assert cs.valid?
873 end
874
875 test "it sets the follower_adress" do
876 cs = User.remote_user_changeset(@valid_remote)
877 # remote users get a fake local follower address
878 assert cs.changes.follower_address ==
879 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
880 end
881
882 test "it enforces the fqn format for nicknames" do
883 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
884 assert Ecto.Changeset.get_field(cs, :local) == false
885 assert cs.changes.avatar
886 refute cs.valid?
887 end
888
889 test "it has required fields" do
890 [:ap_id]
891 |> Enum.each(fn field ->
892 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
893 refute cs.valid?
894 end)
895 end
896 end
897
898 describe "followers and friends" do
899 test "gets all followers for a given user" do
900 user = insert(:user)
901 follower_one = insert(:user)
902 follower_two = insert(:user)
903 not_follower = insert(:user)
904
905 {:ok, follower_one} = User.follow(follower_one, user)
906 {:ok, follower_two} = User.follow(follower_two, user)
907
908 res = User.get_followers(user)
909
910 assert Enum.member?(res, follower_one)
911 assert Enum.member?(res, follower_two)
912 refute Enum.member?(res, not_follower)
913 end
914
915 test "gets all friends (followed users) for a given user" do
916 user = insert(:user)
917 followed_one = insert(:user)
918 followed_two = insert(:user)
919 not_followed = insert(:user)
920
921 {:ok, user} = User.follow(user, followed_one)
922 {:ok, user} = User.follow(user, followed_two)
923
924 res = User.get_friends(user)
925
926 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
927 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
928 assert Enum.member?(res, followed_one)
929 assert Enum.member?(res, followed_two)
930 refute Enum.member?(res, not_followed)
931 end
932 end
933
934 describe "updating note and follower count" do
935 test "it sets the note_count property" do
936 note = insert(:note)
937
938 user = User.get_cached_by_ap_id(note.data["actor"])
939
940 assert user.note_count == 0
941
942 {:ok, user} = User.update_note_count(user)
943
944 assert user.note_count == 1
945 end
946
947 test "it increases the note_count property" do
948 note = insert(:note)
949 user = User.get_cached_by_ap_id(note.data["actor"])
950
951 assert user.note_count == 0
952
953 {:ok, user} = User.increase_note_count(user)
954
955 assert user.note_count == 1
956
957 {:ok, user} = User.increase_note_count(user)
958
959 assert user.note_count == 2
960 end
961
962 test "it decreases the note_count property" do
963 note = insert(:note)
964 user = User.get_cached_by_ap_id(note.data["actor"])
965
966 assert user.note_count == 0
967
968 {:ok, user} = User.increase_note_count(user)
969
970 assert user.note_count == 1
971
972 {:ok, user} = User.decrease_note_count(user)
973
974 assert user.note_count == 0
975
976 {:ok, user} = User.decrease_note_count(user)
977
978 assert user.note_count == 0
979 end
980
981 test "it sets the follower_count property" do
982 user = insert(:user)
983 follower = insert(:user)
984
985 User.follow(follower, user)
986
987 assert user.follower_count == 0
988
989 {:ok, user} = User.update_follower_count(user)
990
991 assert user.follower_count == 1
992 end
993 end
994
995 describe "mutes" do
996 test "it mutes people" do
997 user = insert(:user)
998 muted_user = insert(:user)
999
1000 refute User.mutes?(user, muted_user)
1001 refute User.muted_notifications?(user, muted_user)
1002
1003 {:ok, _user_relationships} = User.mute(user, muted_user)
1004
1005 assert User.mutes?(user, muted_user)
1006 assert User.muted_notifications?(user, muted_user)
1007 end
1008
1009 test "it unmutes users" do
1010 user = insert(:user)
1011 muted_user = insert(:user)
1012
1013 {:ok, _user_relationships} = User.mute(user, muted_user)
1014 {:ok, _user_mute} = User.unmute(user, muted_user)
1015
1016 refute User.mutes?(user, muted_user)
1017 refute User.muted_notifications?(user, muted_user)
1018 end
1019
1020 test "it mutes user without notifications" do
1021 user = insert(:user)
1022 muted_user = insert(:user)
1023
1024 refute User.mutes?(user, muted_user)
1025 refute User.muted_notifications?(user, muted_user)
1026
1027 {:ok, _user_relationships} = User.mute(user, muted_user, false)
1028
1029 assert User.mutes?(user, muted_user)
1030 refute User.muted_notifications?(user, muted_user)
1031 end
1032 end
1033
1034 describe "blocks" do
1035 test "it blocks people" do
1036 user = insert(:user)
1037 blocked_user = insert(:user)
1038
1039 refute User.blocks?(user, blocked_user)
1040
1041 {:ok, _user_relationship} = User.block(user, blocked_user)
1042
1043 assert User.blocks?(user, blocked_user)
1044 end
1045
1046 test "it unblocks users" do
1047 user = insert(:user)
1048 blocked_user = insert(:user)
1049
1050 {:ok, _user_relationship} = User.block(user, blocked_user)
1051 {:ok, _user_block} = User.unblock(user, blocked_user)
1052
1053 refute User.blocks?(user, blocked_user)
1054 end
1055
1056 test "blocks tear down cyclical follow relationships" do
1057 blocker = insert(:user)
1058 blocked = insert(:user)
1059
1060 {:ok, blocker} = User.follow(blocker, blocked)
1061 {:ok, blocked} = User.follow(blocked, blocker)
1062
1063 assert User.following?(blocker, blocked)
1064 assert User.following?(blocked, blocker)
1065
1066 {:ok, _user_relationship} = User.block(blocker, blocked)
1067 blocked = User.get_cached_by_id(blocked.id)
1068
1069 assert User.blocks?(blocker, blocked)
1070
1071 refute User.following?(blocker, blocked)
1072 refute User.following?(blocked, blocker)
1073 end
1074
1075 test "blocks tear down blocker->blocked follow relationships" do
1076 blocker = insert(:user)
1077 blocked = insert(:user)
1078
1079 {:ok, blocker} = User.follow(blocker, blocked)
1080
1081 assert User.following?(blocker, blocked)
1082 refute User.following?(blocked, blocker)
1083
1084 {:ok, _user_relationship} = User.block(blocker, blocked)
1085 blocked = User.get_cached_by_id(blocked.id)
1086
1087 assert User.blocks?(blocker, blocked)
1088
1089 refute User.following?(blocker, blocked)
1090 refute User.following?(blocked, blocker)
1091 end
1092
1093 test "blocks tear down blocked->blocker follow relationships" do
1094 blocker = insert(:user)
1095 blocked = insert(:user)
1096
1097 {:ok, blocked} = User.follow(blocked, blocker)
1098
1099 refute User.following?(blocker, blocked)
1100 assert User.following?(blocked, blocker)
1101
1102 {:ok, _user_relationship} = User.block(blocker, blocked)
1103 blocked = User.get_cached_by_id(blocked.id)
1104
1105 assert User.blocks?(blocker, blocked)
1106
1107 refute User.following?(blocker, blocked)
1108 refute User.following?(blocked, blocker)
1109 end
1110
1111 test "blocks tear down blocked->blocker subscription relationships" do
1112 blocker = insert(:user)
1113 blocked = insert(:user)
1114
1115 {:ok, _subscription} = User.subscribe(blocked, blocker)
1116
1117 assert User.subscribed_to?(blocked, blocker)
1118 refute User.subscribed_to?(blocker, blocked)
1119
1120 {:ok, _user_relationship} = User.block(blocker, blocked)
1121
1122 assert User.blocks?(blocker, blocked)
1123 refute User.subscribed_to?(blocker, blocked)
1124 refute User.subscribed_to?(blocked, blocker)
1125 end
1126 end
1127
1128 describe "domain blocking" do
1129 test "blocks domains" do
1130 user = insert(:user)
1131 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1132
1133 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1134
1135 assert User.blocks?(user, collateral_user)
1136 end
1137
1138 test "does not block domain with same end" do
1139 user = insert(:user)
1140
1141 collateral_user =
1142 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1143
1144 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1145
1146 refute User.blocks?(user, collateral_user)
1147 end
1148
1149 test "does not block domain with same end if wildcard added" do
1150 user = insert(:user)
1151
1152 collateral_user =
1153 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1154
1155 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1156
1157 refute User.blocks?(user, collateral_user)
1158 end
1159
1160 test "blocks domain with wildcard for subdomain" do
1161 user = insert(:user)
1162
1163 user_from_subdomain =
1164 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1165
1166 user_with_two_subdomains =
1167 insert(:user, %{
1168 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1169 })
1170
1171 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1172
1173 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1174
1175 assert User.blocks?(user, user_from_subdomain)
1176 assert User.blocks?(user, user_with_two_subdomains)
1177 assert User.blocks?(user, user_domain)
1178 end
1179
1180 test "unblocks domains" do
1181 user = insert(:user)
1182 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1183
1184 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1185 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1186
1187 refute User.blocks?(user, collateral_user)
1188 end
1189
1190 test "follows take precedence over domain blocks" do
1191 user = insert(:user)
1192 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1193
1194 {:ok, user} = User.block_domain(user, "meanies.social")
1195 {:ok, user} = User.follow(user, good_eggo)
1196
1197 refute User.blocks?(user, good_eggo)
1198 end
1199 end
1200
1201 describe "get_recipients_from_activity" do
1202 test "works for announces" do
1203 actor = insert(:user)
1204 user = insert(:user, local: true)
1205
1206 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1207 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1208
1209 recipients = User.get_recipients_from_activity(announce)
1210
1211 assert user in recipients
1212 end
1213
1214 test "get recipients" do
1215 actor = insert(:user)
1216 user = insert(:user, local: true)
1217 user_two = insert(:user, local: false)
1218 addressed = insert(:user, local: true)
1219 addressed_remote = insert(:user, local: false)
1220
1221 {:ok, activity} =
1222 CommonAPI.post(actor, %{
1223 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1224 })
1225
1226 assert Enum.map([actor, addressed], & &1.ap_id) --
1227 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1228
1229 {:ok, user} = User.follow(user, actor)
1230 {:ok, _user_two} = User.follow(user_two, actor)
1231 recipients = User.get_recipients_from_activity(activity)
1232 assert length(recipients) == 3
1233 assert user in recipients
1234 assert addressed in recipients
1235 end
1236
1237 test "has following" do
1238 actor = insert(:user)
1239 user = insert(:user)
1240 user_two = insert(:user)
1241 addressed = insert(:user, local: true)
1242
1243 {:ok, activity} =
1244 CommonAPI.post(actor, %{
1245 status: "hey @#{addressed.nickname}"
1246 })
1247
1248 assert Enum.map([actor, addressed], & &1.ap_id) --
1249 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1250
1251 {:ok, _actor} = User.follow(actor, user)
1252 {:ok, _actor} = User.follow(actor, user_two)
1253 recipients = User.get_recipients_from_activity(activity)
1254 assert length(recipients) == 2
1255 assert addressed in recipients
1256 end
1257 end
1258
1259 describe ".deactivate" do
1260 test "can de-activate then re-activate a user" do
1261 user = insert(:user)
1262 assert false == user.deactivated
1263 {:ok, user} = User.deactivate(user)
1264 assert true == user.deactivated
1265 {:ok, user} = User.deactivate(user, false)
1266 assert false == user.deactivated
1267 end
1268
1269 test "hide a user from followers" do
1270 user = insert(:user)
1271 user2 = insert(:user)
1272
1273 {:ok, user} = User.follow(user, user2)
1274 {:ok, _user} = User.deactivate(user)
1275
1276 user2 = User.get_cached_by_id(user2.id)
1277
1278 assert user2.follower_count == 0
1279 assert [] = User.get_followers(user2)
1280 end
1281
1282 test "hide a user from friends" do
1283 user = insert(:user)
1284 user2 = insert(:user)
1285
1286 {:ok, user2} = User.follow(user2, user)
1287 assert user2.following_count == 1
1288 assert User.following_count(user2) == 1
1289
1290 {:ok, _user} = User.deactivate(user)
1291
1292 user2 = User.get_cached_by_id(user2.id)
1293
1294 assert refresh_record(user2).following_count == 0
1295 assert user2.following_count == 0
1296 assert User.following_count(user2) == 0
1297 assert [] = User.get_friends(user2)
1298 end
1299
1300 test "hide a user's statuses from timelines and notifications" do
1301 user = insert(:user)
1302 user2 = insert(:user)
1303
1304 {:ok, user2} = User.follow(user2, user)
1305
1306 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1307
1308 activity = Repo.preload(activity, :bookmark)
1309
1310 [notification] = Pleroma.Notification.for_user(user2)
1311 assert notification.activity.id == activity.id
1312
1313 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1314
1315 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1316 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1317 user: user2
1318 })
1319
1320 {:ok, _user} = User.deactivate(user)
1321
1322 assert [] == ActivityPub.fetch_public_activities(%{})
1323 assert [] == Pleroma.Notification.for_user(user2)
1324
1325 assert [] ==
1326 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1327 user: user2
1328 })
1329 end
1330 end
1331
1332 describe "approve" do
1333 test "approves a user" do
1334 user = insert(:user, approval_pending: true)
1335 assert true == user.approval_pending
1336 {:ok, user} = User.approve(user)
1337 assert false == user.approval_pending
1338 end
1339
1340 test "approves a list of users" do
1341 unapproved_users = [
1342 insert(:user, approval_pending: true),
1343 insert(:user, approval_pending: true),
1344 insert(:user, approval_pending: true)
1345 ]
1346
1347 {:ok, users} = User.approve(unapproved_users)
1348
1349 assert Enum.count(users) == 3
1350
1351 Enum.each(users, fn user ->
1352 assert false == user.approval_pending
1353 end)
1354 end
1355 end
1356
1357 describe "delete" do
1358 setup do
1359 {:ok, user} = insert(:user) |> User.set_cache()
1360
1361 [user: user]
1362 end
1363
1364 setup do: clear_config([:instance, :federating])
1365
1366 test ".delete_user_activities deletes all create activities", %{user: user} do
1367 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1368
1369 User.delete_user_activities(user)
1370
1371 # TODO: Test removal favorites, repeats, delete activities.
1372 refute Activity.get_by_id(activity.id)
1373 end
1374
1375 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1376 follower = insert(:user)
1377 {:ok, follower} = User.follow(follower, user)
1378
1379 locked_user = insert(:user, name: "locked", locked: true)
1380 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1381
1382 object = insert(:note, user: user)
1383 activity = insert(:note_activity, user: user, note: object)
1384
1385 object_two = insert(:note, user: follower)
1386 activity_two = insert(:note_activity, user: follower, note: object_two)
1387
1388 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1389 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1390 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1391
1392 {:ok, job} = User.delete(user)
1393 {:ok, _user} = ObanHelpers.perform(job)
1394
1395 follower = User.get_cached_by_id(follower.id)
1396
1397 refute User.following?(follower, user)
1398 assert %{deactivated: true} = User.get_by_id(user.id)
1399
1400 assert [] == User.get_follow_requests(locked_user)
1401
1402 user_activities =
1403 user.ap_id
1404 |> Activity.Queries.by_actor()
1405 |> Repo.all()
1406 |> Enum.map(fn act -> act.data["type"] end)
1407
1408 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1409
1410 refute Activity.get_by_id(activity.id)
1411 refute Activity.get_by_id(like.id)
1412 refute Activity.get_by_id(like_two.id)
1413 refute Activity.get_by_id(repeat.id)
1414 end
1415 end
1416
1417 describe "delete/1 when confirmation is pending" do
1418 setup do
1419 user = insert(:user, confirmation_pending: true)
1420 {:ok, user: user}
1421 end
1422
1423 test "deletes user from database when activation required", %{user: user} do
1424 clear_config([:instance, :account_activation_required], true)
1425
1426 {:ok, job} = User.delete(user)
1427 {:ok, _} = ObanHelpers.perform(job)
1428
1429 refute User.get_cached_by_id(user.id)
1430 refute User.get_by_id(user.id)
1431 end
1432
1433 test "deactivates user when activation is not required", %{user: user} do
1434 clear_config([:instance, :account_activation_required], false)
1435
1436 {:ok, job} = User.delete(user)
1437 {:ok, _} = ObanHelpers.perform(job)
1438
1439 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1440 assert %{deactivated: true} = User.get_by_id(user.id)
1441 end
1442 end
1443
1444 test "delete/1 when approval is pending deletes the user" do
1445 user = insert(:user, approval_pending: true)
1446
1447 {:ok, job} = User.delete(user)
1448 {:ok, _} = ObanHelpers.perform(job)
1449
1450 refute User.get_cached_by_id(user.id)
1451 refute User.get_by_id(user.id)
1452 end
1453
1454 test "delete/1 purges a user when they wouldn't be fully deleted" do
1455 user =
1456 insert(:user, %{
1457 bio: "eyy lmao",
1458 name: "qqqqqqq",
1459 password_hash: "pdfk2$1b3n159001",
1460 keys: "RSA begin buplic key",
1461 public_key: "--PRIVATE KEYE--",
1462 avatar: %{"a" => "b"},
1463 tags: ["qqqqq"],
1464 banner: %{"a" => "b"},
1465 background: %{"a" => "b"},
1466 note_count: 9,
1467 follower_count: 9,
1468 following_count: 9001,
1469 locked: true,
1470 confirmation_pending: true,
1471 password_reset_pending: true,
1472 approval_pending: true,
1473 registration_reason: "ahhhhh",
1474 confirmation_token: "qqqq",
1475 domain_blocks: ["lain.com"],
1476 deactivated: true,
1477 ap_enabled: true,
1478 is_moderator: true,
1479 is_admin: true,
1480 mastofe_settings: %{"a" => "b"},
1481 mascot: %{"a" => "b"},
1482 emoji: %{"a" => "b"},
1483 pleroma_settings_store: %{"q" => "x"},
1484 fields: [%{"gg" => "qq"}],
1485 raw_fields: [%{"gg" => "qq"}],
1486 discoverable: true,
1487 also_known_as: ["https://lol.olo/users/loll"]
1488 })
1489
1490 {:ok, job} = User.delete(user)
1491 {:ok, _} = ObanHelpers.perform(job)
1492 user = User.get_by_id(user.id)
1493
1494 assert %User{
1495 bio: "",
1496 raw_bio: nil,
1497 email: nil,
1498 name: nil,
1499 password_hash: nil,
1500 keys: nil,
1501 public_key: nil,
1502 avatar: %{},
1503 tags: [],
1504 last_refreshed_at: nil,
1505 last_digest_emailed_at: nil,
1506 banner: %{},
1507 background: %{},
1508 note_count: 0,
1509 follower_count: 0,
1510 following_count: 0,
1511 locked: false,
1512 confirmation_pending: false,
1513 password_reset_pending: false,
1514 approval_pending: false,
1515 registration_reason: nil,
1516 confirmation_token: nil,
1517 domain_blocks: [],
1518 deactivated: true,
1519 ap_enabled: false,
1520 is_moderator: false,
1521 is_admin: false,
1522 mastofe_settings: nil,
1523 mascot: nil,
1524 emoji: %{},
1525 pleroma_settings_store: %{},
1526 fields: [],
1527 raw_fields: [],
1528 discoverable: false,
1529 also_known_as: []
1530 } = user
1531 end
1532
1533 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1534 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1535 end
1536
1537 describe "per-user rich-text filtering" do
1538 test "html_filter_policy returns default policies, when rich-text is enabled" do
1539 user = insert(:user)
1540
1541 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1542 end
1543
1544 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1545 user = insert(:user, no_rich_text: true)
1546
1547 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1548 end
1549 end
1550
1551 describe "caching" do
1552 test "invalidate_cache works" do
1553 user = insert(:user)
1554
1555 User.set_cache(user)
1556 User.invalidate_cache(user)
1557
1558 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1559 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1560 end
1561
1562 test "User.delete() plugs any possible zombie objects" do
1563 user = insert(:user)
1564
1565 {:ok, job} = User.delete(user)
1566 {:ok, _} = ObanHelpers.perform(job)
1567
1568 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1569
1570 assert cached_user != user
1571
1572 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1573
1574 assert cached_user != user
1575 end
1576 end
1577
1578 describe "account_status/1" do
1579 setup do: clear_config([:instance, :account_activation_required])
1580
1581 test "return confirmation_pending for unconfirm user" do
1582 Pleroma.Config.put([:instance, :account_activation_required], true)
1583 user = insert(:user, confirmation_pending: true)
1584 assert User.account_status(user) == :confirmation_pending
1585 end
1586
1587 test "return active for confirmed user" do
1588 Pleroma.Config.put([:instance, :account_activation_required], true)
1589 user = insert(:user, confirmation_pending: false)
1590 assert User.account_status(user) == :active
1591 end
1592
1593 test "return active for remote user" do
1594 user = insert(:user, local: false)
1595 assert User.account_status(user) == :active
1596 end
1597
1598 test "returns :password_reset_pending for user with reset password" do
1599 user = insert(:user, password_reset_pending: true)
1600 assert User.account_status(user) == :password_reset_pending
1601 end
1602
1603 test "returns :deactivated for deactivated user" do
1604 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1605 assert User.account_status(user) == :deactivated
1606 end
1607
1608 test "returns :approval_pending for unapproved user" do
1609 user = insert(:user, local: true, approval_pending: true)
1610 assert User.account_status(user) == :approval_pending
1611
1612 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1613 assert User.account_status(user) == :approval_pending
1614 end
1615 end
1616
1617 describe "superuser?/1" do
1618 test "returns false for unprivileged users" do
1619 user = insert(:user, local: true)
1620
1621 refute User.superuser?(user)
1622 end
1623
1624 test "returns false for remote users" do
1625 user = insert(:user, local: false)
1626 remote_admin_user = insert(:user, local: false, is_admin: true)
1627
1628 refute User.superuser?(user)
1629 refute User.superuser?(remote_admin_user)
1630 end
1631
1632 test "returns true for local moderators" do
1633 user = insert(:user, local: true, is_moderator: true)
1634
1635 assert User.superuser?(user)
1636 end
1637
1638 test "returns true for local admins" do
1639 user = insert(:user, local: true, is_admin: true)
1640
1641 assert User.superuser?(user)
1642 end
1643 end
1644
1645 describe "invisible?/1" do
1646 test "returns true for an invisible user" do
1647 user = insert(:user, local: true, invisible: true)
1648
1649 assert User.invisible?(user)
1650 end
1651
1652 test "returns false for a non-invisible user" do
1653 user = insert(:user, local: true)
1654
1655 refute User.invisible?(user)
1656 end
1657 end
1658
1659 describe "visible_for/2" do
1660 test "returns true when the account is itself" do
1661 user = insert(:user, local: true)
1662
1663 assert User.visible_for(user, user) == :visible
1664 end
1665
1666 test "returns false when the account is unconfirmed and confirmation is required" do
1667 Pleroma.Config.put([:instance, :account_activation_required], true)
1668
1669 user = insert(:user, local: true, confirmation_pending: true)
1670 other_user = insert(:user, local: true)
1671
1672 refute User.visible_for(user, other_user) == :visible
1673 end
1674
1675 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1676 Pleroma.Config.put([:instance, :account_activation_required], true)
1677
1678 user = insert(:user, local: false, confirmation_pending: true)
1679 other_user = insert(:user, local: true)
1680
1681 assert User.visible_for(user, other_user) == :visible
1682 end
1683
1684 test "returns true when the account is unconfirmed and confirmation is not required" do
1685 user = insert(:user, local: true, confirmation_pending: true)
1686 other_user = insert(:user, local: true)
1687
1688 assert User.visible_for(user, other_user) == :visible
1689 end
1690
1691 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1692 Pleroma.Config.put([:instance, :account_activation_required], true)
1693
1694 user = insert(:user, local: true, confirmation_pending: true)
1695 other_user = insert(:user, local: true, is_admin: true)
1696
1697 assert User.visible_for(user, other_user) == :visible
1698 end
1699 end
1700
1701 describe "parse_bio/2" do
1702 test "preserves hosts in user links text" do
1703 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1704 user = insert(:user)
1705 bio = "A.k.a. @nick@domain.com"
1706
1707 expected_text =
1708 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1709 remote_user.ap_id
1710 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1711
1712 assert expected_text == User.parse_bio(bio, user)
1713 end
1714
1715 test "Adds rel=me on linkbacked urls" do
1716 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1717
1718 bio = "http://example.com/rel_me/null"
1719 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1720 assert expected_text == User.parse_bio(bio, user)
1721
1722 bio = "http://example.com/rel_me/link"
1723 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1724 assert expected_text == User.parse_bio(bio, user)
1725
1726 bio = "http://example.com/rel_me/anchor"
1727 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1728 assert expected_text == User.parse_bio(bio, user)
1729 end
1730 end
1731
1732 test "follower count is updated when a follower is blocked" do
1733 user = insert(:user)
1734 follower = insert(:user)
1735 follower2 = insert(:user)
1736 follower3 = insert(:user)
1737
1738 {:ok, follower} = User.follow(follower, user)
1739 {:ok, _follower2} = User.follow(follower2, user)
1740 {:ok, _follower3} = User.follow(follower3, user)
1741
1742 {:ok, _user_relationship} = User.block(user, follower)
1743 user = refresh_record(user)
1744
1745 assert user.follower_count == 2
1746 end
1747
1748 describe "list_inactive_users_query/1" do
1749 defp days_ago(days) do
1750 NaiveDateTime.add(
1751 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1752 -days * 60 * 60 * 24,
1753 :second
1754 )
1755 end
1756
1757 test "Users are inactive by default" do
1758 total = 10
1759
1760 users =
1761 Enum.map(1..total, fn _ ->
1762 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1763 end)
1764
1765 inactive_users_ids =
1766 Pleroma.User.list_inactive_users_query()
1767 |> Pleroma.Repo.all()
1768 |> Enum.map(& &1.id)
1769
1770 Enum.each(users, fn user ->
1771 assert user.id in inactive_users_ids
1772 end)
1773 end
1774
1775 test "Only includes users who has no recent activity" do
1776 total = 10
1777
1778 users =
1779 Enum.map(1..total, fn _ ->
1780 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1781 end)
1782
1783 {inactive, active} = Enum.split(users, trunc(total / 2))
1784
1785 Enum.map(active, fn user ->
1786 to = Enum.random(users -- [user])
1787
1788 {:ok, _} =
1789 CommonAPI.post(user, %{
1790 status: "hey @#{to.nickname}"
1791 })
1792 end)
1793
1794 inactive_users_ids =
1795 Pleroma.User.list_inactive_users_query()
1796 |> Pleroma.Repo.all()
1797 |> Enum.map(& &1.id)
1798
1799 Enum.each(active, fn user ->
1800 refute user.id in inactive_users_ids
1801 end)
1802
1803 Enum.each(inactive, fn user ->
1804 assert user.id in inactive_users_ids
1805 end)
1806 end
1807
1808 test "Only includes users with no read notifications" do
1809 total = 10
1810
1811 users =
1812 Enum.map(1..total, fn _ ->
1813 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1814 end)
1815
1816 [sender | recipients] = users
1817 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1818
1819 Enum.each(recipients, fn to ->
1820 {:ok, _} =
1821 CommonAPI.post(sender, %{
1822 status: "hey @#{to.nickname}"
1823 })
1824
1825 {:ok, _} =
1826 CommonAPI.post(sender, %{
1827 status: "hey again @#{to.nickname}"
1828 })
1829 end)
1830
1831 Enum.each(active, fn user ->
1832 [n1, _n2] = Pleroma.Notification.for_user(user)
1833 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1834 end)
1835
1836 inactive_users_ids =
1837 Pleroma.User.list_inactive_users_query()
1838 |> Pleroma.Repo.all()
1839 |> Enum.map(& &1.id)
1840
1841 Enum.each(active, fn user ->
1842 refute user.id in inactive_users_ids
1843 end)
1844
1845 Enum.each(inactive, fn user ->
1846 assert user.id in inactive_users_ids
1847 end)
1848 end
1849 end
1850
1851 describe "toggle_confirmation/1" do
1852 test "if user is confirmed" do
1853 user = insert(:user, confirmation_pending: false)
1854 {:ok, user} = User.toggle_confirmation(user)
1855
1856 assert user.confirmation_pending
1857 assert user.confirmation_token
1858 end
1859
1860 test "if user is unconfirmed" do
1861 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1862 {:ok, user} = User.toggle_confirmation(user)
1863
1864 refute user.confirmation_pending
1865 refute user.confirmation_token
1866 end
1867 end
1868
1869 describe "ensure_keys_present" do
1870 test "it creates keys for a user and stores them in info" do
1871 user = insert(:user)
1872 refute is_binary(user.keys)
1873 {:ok, user} = User.ensure_keys_present(user)
1874 assert is_binary(user.keys)
1875 end
1876
1877 test "it doesn't create keys if there already are some" do
1878 user = insert(:user, keys: "xxx")
1879 {:ok, user} = User.ensure_keys_present(user)
1880 assert user.keys == "xxx"
1881 end
1882 end
1883
1884 describe "get_ap_ids_by_nicknames" do
1885 test "it returns a list of AP ids for a given set of nicknames" do
1886 user = insert(:user)
1887 user_two = insert(:user)
1888
1889 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1890 assert length(ap_ids) == 2
1891 assert user.ap_id in ap_ids
1892 assert user_two.ap_id in ap_ids
1893 end
1894 end
1895
1896 describe "sync followers count" do
1897 setup do
1898 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1899 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1900 insert(:user, local: true)
1901 insert(:user, local: false, deactivated: true)
1902 {:ok, user1: user1, user2: user2}
1903 end
1904
1905 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1906 [fdb_user1] = User.external_users(limit: 1)
1907
1908 assert fdb_user1.ap_id
1909 assert fdb_user1.ap_id == user1.ap_id
1910 assert fdb_user1.id == user1.id
1911
1912 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1913
1914 assert fdb_user2.ap_id
1915 assert fdb_user2.ap_id == user2.ap_id
1916 assert fdb_user2.id == user2.id
1917
1918 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1919 end
1920 end
1921
1922 describe "is_internal_user?/1" do
1923 test "non-internal user returns false" do
1924 user = insert(:user)
1925 refute User.is_internal_user?(user)
1926 end
1927
1928 test "user with no nickname returns true" do
1929 user = insert(:user, %{nickname: nil})
1930 assert User.is_internal_user?(user)
1931 end
1932
1933 test "user with internal-prefixed nickname returns true" do
1934 user = insert(:user, %{nickname: "internal.test"})
1935 assert User.is_internal_user?(user)
1936 end
1937 end
1938
1939 describe "update_and_set_cache/1" do
1940 test "returns error when user is stale instead Ecto.StaleEntryError" do
1941 user = insert(:user)
1942
1943 changeset = Ecto.Changeset.change(user, bio: "test")
1944
1945 Repo.delete(user)
1946
1947 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1948 User.update_and_set_cache(changeset)
1949 end
1950
1951 test "performs update cache if user updated" do
1952 user = insert(:user)
1953 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1954
1955 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1956
1957 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1958 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1959 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1960 end
1961 end
1962
1963 describe "following/followers synchronization" do
1964 setup do: clear_config([:instance, :external_user_synchronization])
1965
1966 test "updates the counters normally on following/getting a follow when disabled" do
1967 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1968 user = insert(:user)
1969
1970 other_user =
1971 insert(:user,
1972 local: false,
1973 follower_address: "http://localhost:4001/users/masto_closed/followers",
1974 following_address: "http://localhost:4001/users/masto_closed/following",
1975 ap_enabled: true
1976 )
1977
1978 assert other_user.following_count == 0
1979 assert other_user.follower_count == 0
1980
1981 {:ok, user} = Pleroma.User.follow(user, other_user)
1982 other_user = Pleroma.User.get_by_id(other_user.id)
1983
1984 assert user.following_count == 1
1985 assert other_user.follower_count == 1
1986 end
1987
1988 test "syncronizes the counters with the remote instance for the followed when enabled" do
1989 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1990
1991 user = insert(:user)
1992
1993 other_user =
1994 insert(:user,
1995 local: false,
1996 follower_address: "http://localhost:4001/users/masto_closed/followers",
1997 following_address: "http://localhost:4001/users/masto_closed/following",
1998 ap_enabled: true
1999 )
2000
2001 assert other_user.following_count == 0
2002 assert other_user.follower_count == 0
2003
2004 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2005 {:ok, _user} = User.follow(user, other_user)
2006 other_user = User.get_by_id(other_user.id)
2007
2008 assert other_user.follower_count == 437
2009 end
2010
2011 test "syncronizes the counters with the remote instance for the follower when enabled" do
2012 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2013
2014 user = insert(:user)
2015
2016 other_user =
2017 insert(:user,
2018 local: false,
2019 follower_address: "http://localhost:4001/users/masto_closed/followers",
2020 following_address: "http://localhost:4001/users/masto_closed/following",
2021 ap_enabled: true
2022 )
2023
2024 assert other_user.following_count == 0
2025 assert other_user.follower_count == 0
2026
2027 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2028 {:ok, other_user} = User.follow(other_user, user)
2029
2030 assert other_user.following_count == 152
2031 end
2032 end
2033
2034 describe "change_email/2" do
2035 setup do
2036 [user: insert(:user)]
2037 end
2038
2039 test "blank email returns error", %{user: user} do
2040 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2041 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2042 end
2043
2044 test "non unique email returns error", %{user: user} do
2045 %{email: email} = insert(:user)
2046
2047 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2048 User.change_email(user, email)
2049 end
2050
2051 test "invalid email returns error", %{user: user} do
2052 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2053 User.change_email(user, "cofe")
2054 end
2055
2056 test "changes email", %{user: user} do
2057 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2058 end
2059 end
2060
2061 describe "get_cached_by_nickname_or_id" do
2062 setup do
2063 local_user = insert(:user)
2064 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2065
2066 [local_user: local_user, remote_user: remote_user]
2067 end
2068
2069 setup do: clear_config([:instance, :limit_to_local_content])
2070
2071 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2072 remote_user: remote_user
2073 } do
2074 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2075 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2076
2077 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2078 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2079
2080 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2081 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2082 end
2083
2084 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2085 %{remote_user: remote_user} do
2086 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2087 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2088 end
2089
2090 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2091 %{remote_user: remote_user, local_user: local_user} do
2092 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2093 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2094 end
2095
2096 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2097 %{remote_user: remote_user} do
2098 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2099 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2100 end
2101
2102 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2103 %{local_user: local_user} do
2104 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2105 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2106
2107 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2108 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2109
2110 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2111 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2112 end
2113 end
2114
2115 describe "update_email_notifications/2" do
2116 setup do
2117 user = insert(:user, email_notifications: %{"digest" => true})
2118
2119 {:ok, user: user}
2120 end
2121
2122 test "Notifications are updated", %{user: user} do
2123 true = user.email_notifications["digest"]
2124 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2125 assert result.email_notifications["digest"] == false
2126 end
2127 end
2128
2129 test "avatar fallback" do
2130 user = insert(:user)
2131 assert User.avatar_url(user) =~ "/images/avi.png"
2132
2133 clear_config([:assets, :default_user_avatar], "avatar.png")
2134
2135 user = User.get_cached_by_nickname_or_id(user.nickname)
2136 assert User.avatar_url(user) =~ "avatar.png"
2137
2138 assert User.avatar_url(user, no_default: true) == nil
2139 end
2140 end