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