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