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