Merge remote-tracking branch 'remotes/origin/develop' into auth-improvements
[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
899 test "it is invalid given a local user" do
900 user = insert(:user)
901 cs = User.remote_user_changeset(user, %{name: "tom from myspace"})
902
903 refute cs.valid?
904 end
905 end
906
907 describe "followers and friends" do
908 test "gets all followers for a given user" do
909 user = insert(:user)
910 follower_one = insert(:user)
911 follower_two = insert(:user)
912 not_follower = insert(:user)
913
914 {:ok, follower_one} = User.follow(follower_one, user)
915 {:ok, follower_two} = User.follow(follower_two, user)
916
917 res = User.get_followers(user)
918
919 assert Enum.member?(res, follower_one)
920 assert Enum.member?(res, follower_two)
921 refute Enum.member?(res, not_follower)
922 end
923
924 test "gets all friends (followed users) for a given user" do
925 user = insert(:user)
926 followed_one = insert(:user)
927 followed_two = insert(:user)
928 not_followed = insert(:user)
929
930 {:ok, user} = User.follow(user, followed_one)
931 {:ok, user} = User.follow(user, followed_two)
932
933 res = User.get_friends(user)
934
935 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
936 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
937 assert Enum.member?(res, followed_one)
938 assert Enum.member?(res, followed_two)
939 refute Enum.member?(res, not_followed)
940 end
941 end
942
943 describe "updating note and follower count" do
944 test "it sets the note_count property" do
945 note = insert(:note)
946
947 user = User.get_cached_by_ap_id(note.data["actor"])
948
949 assert user.note_count == 0
950
951 {:ok, user} = User.update_note_count(user)
952
953 assert user.note_count == 1
954 end
955
956 test "it increases the note_count property" do
957 note = insert(:note)
958 user = User.get_cached_by_ap_id(note.data["actor"])
959
960 assert user.note_count == 0
961
962 {:ok, user} = User.increase_note_count(user)
963
964 assert user.note_count == 1
965
966 {:ok, user} = User.increase_note_count(user)
967
968 assert user.note_count == 2
969 end
970
971 test "it decreases the note_count property" do
972 note = insert(:note)
973 user = User.get_cached_by_ap_id(note.data["actor"])
974
975 assert user.note_count == 0
976
977 {:ok, user} = User.increase_note_count(user)
978
979 assert user.note_count == 1
980
981 {:ok, user} = User.decrease_note_count(user)
982
983 assert user.note_count == 0
984
985 {:ok, user} = User.decrease_note_count(user)
986
987 assert user.note_count == 0
988 end
989
990 test "it sets the follower_count property" do
991 user = insert(:user)
992 follower = insert(:user)
993
994 User.follow(follower, user)
995
996 assert user.follower_count == 0
997
998 {:ok, user} = User.update_follower_count(user)
999
1000 assert user.follower_count == 1
1001 end
1002 end
1003
1004 describe "mutes" do
1005 test "it mutes people" do
1006 user = insert(:user)
1007 muted_user = insert(:user)
1008
1009 refute User.mutes?(user, muted_user)
1010 refute User.muted_notifications?(user, muted_user)
1011
1012 {:ok, _user_relationships} = User.mute(user, muted_user)
1013
1014 assert User.mutes?(user, muted_user)
1015 assert User.muted_notifications?(user, muted_user)
1016 end
1017
1018 test "expiring" do
1019 user = insert(:user)
1020 muted_user = insert(:user)
1021
1022 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
1023 assert User.mutes?(user, muted_user)
1024
1025 worker = Pleroma.Workers.MuteExpireWorker
1026 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
1027
1028 assert_enqueued(
1029 worker: worker,
1030 args: args
1031 )
1032
1033 assert :ok = perform_job(worker, args)
1034
1035 refute User.mutes?(user, muted_user)
1036 refute User.muted_notifications?(user, muted_user)
1037 end
1038
1039 test "it unmutes users" do
1040 user = insert(:user)
1041 muted_user = insert(:user)
1042
1043 {:ok, _user_relationships} = User.mute(user, muted_user)
1044 {:ok, _user_mute} = User.unmute(user, muted_user)
1045
1046 refute User.mutes?(user, muted_user)
1047 refute User.muted_notifications?(user, muted_user)
1048 end
1049
1050 test "it unmutes users by id" do
1051 user = insert(:user)
1052 muted_user = insert(:user)
1053
1054 {:ok, _user_relationships} = User.mute(user, muted_user)
1055 {:ok, _user_mute} = User.unmute(user.id, muted_user.id)
1056
1057 refute User.mutes?(user, muted_user)
1058 refute User.muted_notifications?(user, muted_user)
1059 end
1060
1061 test "it mutes user without notifications" do
1062 user = insert(:user)
1063 muted_user = insert(:user)
1064
1065 refute User.mutes?(user, muted_user)
1066 refute User.muted_notifications?(user, muted_user)
1067
1068 {:ok, _user_relationships} = User.mute(user, muted_user, %{notifications: false})
1069
1070 assert User.mutes?(user, muted_user)
1071 refute User.muted_notifications?(user, muted_user)
1072 end
1073 end
1074
1075 describe "blocks" do
1076 test "it blocks people" do
1077 user = insert(:user)
1078 blocked_user = insert(:user)
1079
1080 refute User.blocks?(user, blocked_user)
1081
1082 {:ok, _user_relationship} = User.block(user, blocked_user)
1083
1084 assert User.blocks?(user, blocked_user)
1085 end
1086
1087 test "it unblocks users" do
1088 user = insert(:user)
1089 blocked_user = insert(:user)
1090
1091 {:ok, _user_relationship} = User.block(user, blocked_user)
1092 {:ok, _user_block} = User.unblock(user, blocked_user)
1093
1094 refute User.blocks?(user, blocked_user)
1095 end
1096
1097 test "blocks tear down cyclical follow relationships" do
1098 blocker = insert(:user)
1099 blocked = insert(:user)
1100
1101 {:ok, blocker} = User.follow(blocker, blocked)
1102 {:ok, blocked} = User.follow(blocked, blocker)
1103
1104 assert User.following?(blocker, blocked)
1105 assert User.following?(blocked, blocker)
1106
1107 {:ok, _user_relationship} = User.block(blocker, blocked)
1108 blocked = User.get_cached_by_id(blocked.id)
1109
1110 assert User.blocks?(blocker, blocked)
1111
1112 refute User.following?(blocker, blocked)
1113 refute User.following?(blocked, blocker)
1114 end
1115
1116 test "blocks tear down blocker->blocked follow relationships" do
1117 blocker = insert(:user)
1118 blocked = insert(:user)
1119
1120 {:ok, blocker} = User.follow(blocker, blocked)
1121
1122 assert User.following?(blocker, blocked)
1123 refute User.following?(blocked, blocker)
1124
1125 {:ok, _user_relationship} = User.block(blocker, blocked)
1126 blocked = User.get_cached_by_id(blocked.id)
1127
1128 assert User.blocks?(blocker, blocked)
1129
1130 refute User.following?(blocker, blocked)
1131 refute User.following?(blocked, blocker)
1132 end
1133
1134 test "blocks tear down blocked->blocker follow relationships" do
1135 blocker = insert(:user)
1136 blocked = insert(:user)
1137
1138 {:ok, blocked} = User.follow(blocked, blocker)
1139
1140 refute User.following?(blocker, blocked)
1141 assert User.following?(blocked, blocker)
1142
1143 {:ok, _user_relationship} = User.block(blocker, blocked)
1144 blocked = User.get_cached_by_id(blocked.id)
1145
1146 assert User.blocks?(blocker, blocked)
1147
1148 refute User.following?(blocker, blocked)
1149 refute User.following?(blocked, blocker)
1150 end
1151
1152 test "blocks tear down blocked->blocker subscription relationships" do
1153 blocker = insert(:user)
1154 blocked = insert(:user)
1155
1156 {:ok, _subscription} = User.subscribe(blocked, blocker)
1157
1158 assert User.subscribed_to?(blocked, blocker)
1159 refute User.subscribed_to?(blocker, blocked)
1160
1161 {:ok, _user_relationship} = User.block(blocker, blocked)
1162
1163 assert User.blocks?(blocker, blocked)
1164 refute User.subscribed_to?(blocker, blocked)
1165 refute User.subscribed_to?(blocked, blocker)
1166 end
1167 end
1168
1169 describe "domain blocking" do
1170 test "blocks domains" do
1171 user = insert(:user)
1172 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1173
1174 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1175
1176 assert User.blocks?(user, collateral_user)
1177 end
1178
1179 test "does not block domain with same end" do
1180 user = insert(:user)
1181
1182 collateral_user =
1183 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1184
1185 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1186
1187 refute User.blocks?(user, collateral_user)
1188 end
1189
1190 test "does not block domain with same end if wildcard added" do
1191 user = insert(:user)
1192
1193 collateral_user =
1194 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1195
1196 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1197
1198 refute User.blocks?(user, collateral_user)
1199 end
1200
1201 test "blocks domain with wildcard for subdomain" do
1202 user = insert(:user)
1203
1204 user_from_subdomain =
1205 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1206
1207 user_with_two_subdomains =
1208 insert(:user, %{
1209 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1210 })
1211
1212 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1213
1214 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1215
1216 assert User.blocks?(user, user_from_subdomain)
1217 assert User.blocks?(user, user_with_two_subdomains)
1218 assert User.blocks?(user, user_domain)
1219 end
1220
1221 test "unblocks domains" do
1222 user = insert(:user)
1223 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1224
1225 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1226 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1227
1228 refute User.blocks?(user, collateral_user)
1229 end
1230
1231 test "follows take precedence over domain blocks" do
1232 user = insert(:user)
1233 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1234
1235 {:ok, user} = User.block_domain(user, "meanies.social")
1236 {:ok, user} = User.follow(user, good_eggo)
1237
1238 refute User.blocks?(user, good_eggo)
1239 end
1240 end
1241
1242 describe "get_recipients_from_activity" do
1243 test "works for announces" do
1244 actor = insert(:user)
1245 user = insert(:user, local: true)
1246
1247 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1248 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1249
1250 recipients = User.get_recipients_from_activity(announce)
1251
1252 assert user in recipients
1253 end
1254
1255 test "get recipients" do
1256 actor = insert(:user)
1257 user = insert(:user, local: true)
1258 user_two = insert(:user, local: false)
1259 addressed = insert(:user, local: true)
1260 addressed_remote = insert(:user, local: false)
1261
1262 {:ok, activity} =
1263 CommonAPI.post(actor, %{
1264 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1265 })
1266
1267 assert Enum.map([actor, addressed], & &1.ap_id) --
1268 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1269
1270 {:ok, user} = User.follow(user, actor)
1271 {:ok, _user_two} = User.follow(user_two, actor)
1272 recipients = User.get_recipients_from_activity(activity)
1273 assert length(recipients) == 3
1274 assert user in recipients
1275 assert addressed in recipients
1276 end
1277
1278 test "has following" do
1279 actor = insert(:user)
1280 user = insert(:user)
1281 user_two = insert(:user)
1282 addressed = insert(:user, local: true)
1283
1284 {:ok, activity} =
1285 CommonAPI.post(actor, %{
1286 status: "hey @#{addressed.nickname}"
1287 })
1288
1289 assert Enum.map([actor, addressed], & &1.ap_id) --
1290 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1291
1292 {:ok, _actor} = User.follow(actor, user)
1293 {:ok, _actor} = User.follow(actor, user_two)
1294 recipients = User.get_recipients_from_activity(activity)
1295 assert length(recipients) == 2
1296 assert addressed in recipients
1297 end
1298 end
1299
1300 describe ".deactivate" do
1301 test "can de-activate then re-activate a user" do
1302 user = insert(:user)
1303 assert false == user.deactivated
1304 {:ok, user} = User.deactivate(user)
1305 assert true == user.deactivated
1306 {:ok, user} = User.deactivate(user, false)
1307 assert false == user.deactivated
1308 end
1309
1310 test "hide a user from followers" do
1311 user = insert(:user)
1312 user2 = insert(:user)
1313
1314 {:ok, user} = User.follow(user, user2)
1315 {:ok, _user} = User.deactivate(user)
1316
1317 user2 = User.get_cached_by_id(user2.id)
1318
1319 assert user2.follower_count == 0
1320 assert [] = User.get_followers(user2)
1321 end
1322
1323 test "hide a user from friends" do
1324 user = insert(:user)
1325 user2 = insert(:user)
1326
1327 {:ok, user2} = User.follow(user2, user)
1328 assert user2.following_count == 1
1329 assert User.following_count(user2) == 1
1330
1331 {:ok, _user} = User.deactivate(user)
1332
1333 user2 = User.get_cached_by_id(user2.id)
1334
1335 assert refresh_record(user2).following_count == 0
1336 assert user2.following_count == 0
1337 assert User.following_count(user2) == 0
1338 assert [] = User.get_friends(user2)
1339 end
1340
1341 test "hide a user's statuses from timelines and notifications" do
1342 user = insert(:user)
1343 user2 = insert(:user)
1344
1345 {:ok, user2} = User.follow(user2, user)
1346
1347 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1348
1349 activity = Repo.preload(activity, :bookmark)
1350
1351 [notification] = Pleroma.Notification.for_user(user2)
1352 assert notification.activity.id == activity.id
1353
1354 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1355
1356 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1357 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1358 user: user2
1359 })
1360
1361 {:ok, _user} = User.deactivate(user)
1362
1363 assert [] == ActivityPub.fetch_public_activities(%{})
1364 assert [] == Pleroma.Notification.for_user(user2)
1365
1366 assert [] ==
1367 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1368 user: user2
1369 })
1370 end
1371 end
1372
1373 describe "approve" do
1374 test "approves a user" do
1375 user = insert(:user, approval_pending: true)
1376 assert true == user.approval_pending
1377 {:ok, user} = User.approve(user)
1378 assert false == user.approval_pending
1379 end
1380
1381 test "approves a list of users" do
1382 unapproved_users = [
1383 insert(:user, approval_pending: true),
1384 insert(:user, approval_pending: true),
1385 insert(:user, approval_pending: true)
1386 ]
1387
1388 {:ok, users} = User.approve(unapproved_users)
1389
1390 assert Enum.count(users) == 3
1391
1392 Enum.each(users, fn user ->
1393 assert false == user.approval_pending
1394 end)
1395 end
1396 end
1397
1398 describe "delete" do
1399 setup do
1400 {:ok, user} = insert(:user) |> User.set_cache()
1401
1402 [user: user]
1403 end
1404
1405 setup do: clear_config([:instance, :federating])
1406
1407 test ".delete_user_activities deletes all create activities", %{user: user} do
1408 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1409
1410 User.delete_user_activities(user)
1411
1412 # TODO: Test removal favorites, repeats, delete activities.
1413 refute Activity.get_by_id(activity.id)
1414 end
1415
1416 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1417 follower = insert(:user)
1418 {:ok, follower} = User.follow(follower, user)
1419
1420 locked_user = insert(:user, name: "locked", is_locked: true)
1421 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1422
1423 object = insert(:note, user: user)
1424 activity = insert(:note_activity, user: user, note: object)
1425
1426 object_two = insert(:note, user: follower)
1427 activity_two = insert(:note_activity, user: follower, note: object_two)
1428
1429 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1430 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1431 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1432
1433 {:ok, job} = User.delete(user)
1434 {:ok, _user} = ObanHelpers.perform(job)
1435
1436 follower = User.get_cached_by_id(follower.id)
1437
1438 refute User.following?(follower, user)
1439 assert %{deactivated: true} = User.get_by_id(user.id)
1440
1441 assert [] == User.get_follow_requests(locked_user)
1442
1443 user_activities =
1444 user.ap_id
1445 |> Activity.Queries.by_actor()
1446 |> Repo.all()
1447 |> Enum.map(fn act -> act.data["type"] end)
1448
1449 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1450
1451 refute Activity.get_by_id(activity.id)
1452 refute Activity.get_by_id(like.id)
1453 refute Activity.get_by_id(like_two.id)
1454 refute Activity.get_by_id(repeat.id)
1455 end
1456 end
1457
1458 describe "delete/1 when confirmation is pending" do
1459 setup do
1460 user = insert(:user, confirmation_pending: true)
1461 {:ok, user: user}
1462 end
1463
1464 test "deletes user from database when activation required", %{user: user} do
1465 clear_config([:instance, :account_activation_required], true)
1466
1467 {:ok, job} = User.delete(user)
1468 {:ok, _} = ObanHelpers.perform(job)
1469
1470 refute User.get_cached_by_id(user.id)
1471 refute User.get_by_id(user.id)
1472 end
1473
1474 test "deactivates user when activation is not required", %{user: user} do
1475 clear_config([:instance, :account_activation_required], false)
1476
1477 {:ok, job} = User.delete(user)
1478 {:ok, _} = ObanHelpers.perform(job)
1479
1480 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1481 assert %{deactivated: true} = User.get_by_id(user.id)
1482 end
1483 end
1484
1485 test "delete/1 when approval is pending deletes the user" do
1486 user = insert(:user, approval_pending: true)
1487
1488 {:ok, job} = User.delete(user)
1489 {:ok, _} = ObanHelpers.perform(job)
1490
1491 refute User.get_cached_by_id(user.id)
1492 refute User.get_by_id(user.id)
1493 end
1494
1495 test "delete/1 purges a user when they wouldn't be fully deleted" do
1496 user =
1497 insert(:user, %{
1498 bio: "eyy lmao",
1499 name: "qqqqqqq",
1500 password_hash: "pdfk2$1b3n159001",
1501 keys: "RSA begin buplic key",
1502 public_key: "--PRIVATE KEYE--",
1503 avatar: %{"a" => "b"},
1504 tags: ["qqqqq"],
1505 banner: %{"a" => "b"},
1506 background: %{"a" => "b"},
1507 note_count: 9,
1508 follower_count: 9,
1509 following_count: 9001,
1510 is_locked: true,
1511 confirmation_pending: true,
1512 password_reset_pending: true,
1513 approval_pending: true,
1514 registration_reason: "ahhhhh",
1515 confirmation_token: "qqqq",
1516 domain_blocks: ["lain.com"],
1517 deactivated: true,
1518 ap_enabled: true,
1519 is_moderator: true,
1520 is_admin: true,
1521 mastofe_settings: %{"a" => "b"},
1522 mascot: %{"a" => "b"},
1523 emoji: %{"a" => "b"},
1524 pleroma_settings_store: %{"q" => "x"},
1525 fields: [%{"gg" => "qq"}],
1526 raw_fields: [%{"gg" => "qq"}],
1527 is_discoverable: true,
1528 also_known_as: ["https://lol.olo/users/loll"]
1529 })
1530
1531 {:ok, job} = User.delete(user)
1532 {:ok, _} = ObanHelpers.perform(job)
1533 user = User.get_by_id(user.id)
1534
1535 assert %User{
1536 bio: "",
1537 raw_bio: nil,
1538 email: nil,
1539 name: nil,
1540 password_hash: nil,
1541 keys: nil,
1542 public_key: nil,
1543 avatar: %{},
1544 tags: [],
1545 last_refreshed_at: nil,
1546 last_digest_emailed_at: nil,
1547 banner: %{},
1548 background: %{},
1549 note_count: 0,
1550 follower_count: 0,
1551 following_count: 0,
1552 is_locked: false,
1553 confirmation_pending: false,
1554 password_reset_pending: false,
1555 approval_pending: false,
1556 registration_reason: nil,
1557 confirmation_token: nil,
1558 domain_blocks: [],
1559 deactivated: true,
1560 ap_enabled: false,
1561 is_moderator: false,
1562 is_admin: false,
1563 mastofe_settings: nil,
1564 mascot: nil,
1565 emoji: %{},
1566 pleroma_settings_store: %{},
1567 fields: [],
1568 raw_fields: [],
1569 is_discoverable: false,
1570 also_known_as: []
1571 } = user
1572 end
1573
1574 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1575 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1576 end
1577
1578 describe "per-user rich-text filtering" do
1579 test "html_filter_policy returns default policies, when rich-text is enabled" do
1580 user = insert(:user)
1581
1582 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1583 end
1584
1585 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1586 user = insert(:user, no_rich_text: true)
1587
1588 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1589 end
1590 end
1591
1592 describe "caching" do
1593 test "invalidate_cache works" do
1594 user = insert(:user)
1595
1596 User.set_cache(user)
1597 User.invalidate_cache(user)
1598
1599 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1600 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1601 end
1602
1603 test "User.delete() plugs any possible zombie objects" do
1604 user = insert(:user)
1605
1606 {:ok, job} = User.delete(user)
1607 {:ok, _} = ObanHelpers.perform(job)
1608
1609 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1610
1611 assert cached_user != user
1612
1613 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1614
1615 assert cached_user != user
1616 end
1617 end
1618
1619 describe "account_status/1" do
1620 setup do: clear_config([:instance, :account_activation_required])
1621
1622 test "return confirmation_pending for unconfirm user" do
1623 Pleroma.Config.put([:instance, :account_activation_required], true)
1624 user = insert(:user, confirmation_pending: true)
1625 assert User.account_status(user) == :confirmation_pending
1626 end
1627
1628 test "return active for confirmed user" do
1629 Pleroma.Config.put([:instance, :account_activation_required], true)
1630 user = insert(:user, confirmation_pending: false)
1631 assert User.account_status(user) == :active
1632 end
1633
1634 test "return active for remote user" do
1635 user = insert(:user, local: false)
1636 assert User.account_status(user) == :active
1637 end
1638
1639 test "returns :password_reset_pending for user with reset password" do
1640 user = insert(:user, password_reset_pending: true)
1641 assert User.account_status(user) == :password_reset_pending
1642 end
1643
1644 test "returns :deactivated for deactivated user" do
1645 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1646 assert User.account_status(user) == :deactivated
1647 end
1648
1649 test "returns :approval_pending for unapproved user" do
1650 user = insert(:user, local: true, approval_pending: true)
1651 assert User.account_status(user) == :approval_pending
1652
1653 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1654 assert User.account_status(user) == :approval_pending
1655 end
1656 end
1657
1658 describe "superuser?/1" do
1659 test "returns false for unprivileged users" do
1660 user = insert(:user, local: true)
1661
1662 refute User.superuser?(user)
1663 end
1664
1665 test "returns false for remote users" do
1666 user = insert(:user, local: false)
1667 remote_admin_user = insert(:user, local: false, is_admin: true)
1668
1669 refute User.superuser?(user)
1670 refute User.superuser?(remote_admin_user)
1671 end
1672
1673 test "returns true for local moderators" do
1674 user = insert(:user, local: true, is_moderator: true)
1675
1676 assert User.superuser?(user)
1677 end
1678
1679 test "returns true for local admins" do
1680 user = insert(:user, local: true, is_admin: true)
1681
1682 assert User.superuser?(user)
1683 end
1684 end
1685
1686 describe "invisible?/1" do
1687 test "returns true for an invisible user" do
1688 user = insert(:user, local: true, invisible: true)
1689
1690 assert User.invisible?(user)
1691 end
1692
1693 test "returns false for a non-invisible user" do
1694 user = insert(:user, local: true)
1695
1696 refute User.invisible?(user)
1697 end
1698 end
1699
1700 describe "visible_for/2" do
1701 test "returns true when the account is itself" do
1702 user = insert(:user, local: true)
1703
1704 assert User.visible_for(user, user) == :visible
1705 end
1706
1707 test "returns false when the account is unconfirmed and confirmation is required" do
1708 Pleroma.Config.put([:instance, :account_activation_required], true)
1709
1710 user = insert(:user, local: true, confirmation_pending: true)
1711 other_user = insert(:user, local: true)
1712
1713 refute User.visible_for(user, other_user) == :visible
1714 end
1715
1716 test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
1717 Pleroma.Config.put([:instance, :account_activation_required], true)
1718
1719 user = insert(:user, local: false, 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 confirmation is not required" do
1726 user = insert(:user, local: true, confirmation_pending: true)
1727 other_user = insert(:user, local: true)
1728
1729 assert User.visible_for(user, other_user) == :visible
1730 end
1731
1732 test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
1733 Pleroma.Config.put([:instance, :account_activation_required], true)
1734
1735 user = insert(:user, local: true, confirmation_pending: true)
1736 other_user = insert(:user, local: true, is_admin: true)
1737
1738 assert User.visible_for(user, other_user) == :visible
1739 end
1740 end
1741
1742 describe "parse_bio/2" do
1743 test "preserves hosts in user links text" do
1744 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1745 user = insert(:user)
1746 bio = "A.k.a. @nick@domain.com"
1747
1748 expected_text =
1749 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1750 remote_user.ap_id
1751 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1752
1753 assert expected_text == User.parse_bio(bio, user)
1754 end
1755
1756 test "Adds rel=me on linkbacked urls" do
1757 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1758
1759 bio = "http://example.com/rel_me/null"
1760 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1761 assert expected_text == User.parse_bio(bio, user)
1762
1763 bio = "http://example.com/rel_me/link"
1764 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1765 assert expected_text == User.parse_bio(bio, user)
1766
1767 bio = "http://example.com/rel_me/anchor"
1768 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1769 assert expected_text == User.parse_bio(bio, user)
1770 end
1771 end
1772
1773 test "follower count is updated when a follower is blocked" do
1774 user = insert(:user)
1775 follower = insert(:user)
1776 follower2 = insert(:user)
1777 follower3 = insert(:user)
1778
1779 {:ok, follower} = User.follow(follower, user)
1780 {:ok, _follower2} = User.follow(follower2, user)
1781 {:ok, _follower3} = User.follow(follower3, user)
1782
1783 {:ok, _user_relationship} = User.block(user, follower)
1784 user = refresh_record(user)
1785
1786 assert user.follower_count == 2
1787 end
1788
1789 describe "list_inactive_users_query/1" do
1790 defp days_ago(days) do
1791 NaiveDateTime.add(
1792 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1793 -days * 60 * 60 * 24,
1794 :second
1795 )
1796 end
1797
1798 test "Users are inactive by default" do
1799 total = 10
1800
1801 users =
1802 Enum.map(1..total, fn _ ->
1803 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1804 end)
1805
1806 inactive_users_ids =
1807 Pleroma.User.list_inactive_users_query()
1808 |> Pleroma.Repo.all()
1809 |> Enum.map(& &1.id)
1810
1811 Enum.each(users, fn user ->
1812 assert user.id in inactive_users_ids
1813 end)
1814 end
1815
1816 test "Only includes users who has no recent activity" do
1817 total = 10
1818
1819 users =
1820 Enum.map(1..total, fn _ ->
1821 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1822 end)
1823
1824 {inactive, active} = Enum.split(users, trunc(total / 2))
1825
1826 Enum.map(active, fn user ->
1827 to = Enum.random(users -- [user])
1828
1829 {:ok, _} =
1830 CommonAPI.post(user, %{
1831 status: "hey @#{to.nickname}"
1832 })
1833 end)
1834
1835 inactive_users_ids =
1836 Pleroma.User.list_inactive_users_query()
1837 |> Pleroma.Repo.all()
1838 |> Enum.map(& &1.id)
1839
1840 Enum.each(active, fn user ->
1841 refute user.id in inactive_users_ids
1842 end)
1843
1844 Enum.each(inactive, fn user ->
1845 assert user.id in inactive_users_ids
1846 end)
1847 end
1848
1849 test "Only includes users with no read notifications" do
1850 total = 10
1851
1852 users =
1853 Enum.map(1..total, fn _ ->
1854 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1855 end)
1856
1857 [sender | recipients] = users
1858 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1859
1860 Enum.each(recipients, fn to ->
1861 {:ok, _} =
1862 CommonAPI.post(sender, %{
1863 status: "hey @#{to.nickname}"
1864 })
1865
1866 {:ok, _} =
1867 CommonAPI.post(sender, %{
1868 status: "hey again @#{to.nickname}"
1869 })
1870 end)
1871
1872 Enum.each(active, fn user ->
1873 [n1, _n2] = Pleroma.Notification.for_user(user)
1874 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1875 end)
1876
1877 inactive_users_ids =
1878 Pleroma.User.list_inactive_users_query()
1879 |> Pleroma.Repo.all()
1880 |> Enum.map(& &1.id)
1881
1882 Enum.each(active, fn user ->
1883 refute user.id in inactive_users_ids
1884 end)
1885
1886 Enum.each(inactive, fn user ->
1887 assert user.id in inactive_users_ids
1888 end)
1889 end
1890 end
1891
1892 describe "toggle_confirmation/1" do
1893 test "if user is confirmed" do
1894 user = insert(:user, confirmation_pending: false)
1895 {:ok, user} = User.toggle_confirmation(user)
1896
1897 assert user.confirmation_pending
1898 assert user.confirmation_token
1899 end
1900
1901 test "if user is unconfirmed" do
1902 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1903 {:ok, user} = User.toggle_confirmation(user)
1904
1905 refute user.confirmation_pending
1906 refute user.confirmation_token
1907 end
1908 end
1909
1910 describe "ensure_keys_present" do
1911 test "it creates keys for a user and stores them in info" do
1912 user = insert(:user)
1913 refute is_binary(user.keys)
1914 {:ok, user} = User.ensure_keys_present(user)
1915 assert is_binary(user.keys)
1916 end
1917
1918 test "it doesn't create keys if there already are some" do
1919 user = insert(:user, keys: "xxx")
1920 {:ok, user} = User.ensure_keys_present(user)
1921 assert user.keys == "xxx"
1922 end
1923 end
1924
1925 describe "get_ap_ids_by_nicknames" do
1926 test "it returns a list of AP ids for a given set of nicknames" do
1927 user = insert(:user)
1928 user_two = insert(:user)
1929
1930 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1931 assert length(ap_ids) == 2
1932 assert user.ap_id in ap_ids
1933 assert user_two.ap_id in ap_ids
1934 end
1935 end
1936
1937 describe "sync followers count" do
1938 setup do
1939 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1940 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1941 insert(:user, local: true)
1942 insert(:user, local: false, deactivated: true)
1943 {:ok, user1: user1, user2: user2}
1944 end
1945
1946 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1947 [fdb_user1] = User.external_users(limit: 1)
1948
1949 assert fdb_user1.ap_id
1950 assert fdb_user1.ap_id == user1.ap_id
1951 assert fdb_user1.id == user1.id
1952
1953 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1954
1955 assert fdb_user2.ap_id
1956 assert fdb_user2.ap_id == user2.ap_id
1957 assert fdb_user2.id == user2.id
1958
1959 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1960 end
1961 end
1962
1963 describe "is_internal_user?/1" do
1964 test "non-internal user returns false" do
1965 user = insert(:user)
1966 refute User.is_internal_user?(user)
1967 end
1968
1969 test "user with no nickname returns true" do
1970 user = insert(:user, %{nickname: nil})
1971 assert User.is_internal_user?(user)
1972 end
1973
1974 test "user with internal-prefixed nickname returns true" do
1975 user = insert(:user, %{nickname: "internal.test"})
1976 assert User.is_internal_user?(user)
1977 end
1978 end
1979
1980 describe "update_and_set_cache/1" do
1981 test "returns error when user is stale instead Ecto.StaleEntryError" do
1982 user = insert(:user)
1983
1984 changeset = Ecto.Changeset.change(user, bio: "test")
1985
1986 Repo.delete(user)
1987
1988 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1989 User.update_and_set_cache(changeset)
1990 end
1991
1992 test "performs update cache if user updated" do
1993 user = insert(:user)
1994 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1995
1996 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1997
1998 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1999 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
2000 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
2001 end
2002 end
2003
2004 describe "following/followers synchronization" do
2005 setup do: clear_config([:instance, :external_user_synchronization])
2006
2007 test "updates the counters normally on following/getting a follow when disabled" do
2008 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2009 user = insert(:user)
2010
2011 other_user =
2012 insert(:user,
2013 local: false,
2014 follower_address: "http://localhost:4001/users/masto_closed/followers",
2015 following_address: "http://localhost:4001/users/masto_closed/following",
2016 ap_enabled: true
2017 )
2018
2019 assert other_user.following_count == 0
2020 assert other_user.follower_count == 0
2021
2022 {:ok, user} = Pleroma.User.follow(user, other_user)
2023 other_user = Pleroma.User.get_by_id(other_user.id)
2024
2025 assert user.following_count == 1
2026 assert other_user.follower_count == 1
2027 end
2028
2029 test "syncronizes the counters with the remote instance for the followed when enabled" do
2030 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2031
2032 user = insert(:user)
2033
2034 other_user =
2035 insert(:user,
2036 local: false,
2037 follower_address: "http://localhost:4001/users/masto_closed/followers",
2038 following_address: "http://localhost:4001/users/masto_closed/following",
2039 ap_enabled: true
2040 )
2041
2042 assert other_user.following_count == 0
2043 assert other_user.follower_count == 0
2044
2045 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2046 {:ok, _user} = User.follow(user, other_user)
2047 other_user = User.get_by_id(other_user.id)
2048
2049 assert other_user.follower_count == 437
2050 end
2051
2052 test "syncronizes the counters with the remote instance for the follower when enabled" do
2053 Pleroma.Config.put([:instance, :external_user_synchronization], false)
2054
2055 user = insert(:user)
2056
2057 other_user =
2058 insert(:user,
2059 local: false,
2060 follower_address: "http://localhost:4001/users/masto_closed/followers",
2061 following_address: "http://localhost:4001/users/masto_closed/following",
2062 ap_enabled: true
2063 )
2064
2065 assert other_user.following_count == 0
2066 assert other_user.follower_count == 0
2067
2068 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2069 {:ok, other_user} = User.follow(other_user, user)
2070
2071 assert other_user.following_count == 152
2072 end
2073 end
2074
2075 describe "change_email/2" do
2076 setup do
2077 [user: insert(:user)]
2078 end
2079
2080 test "blank email returns error", %{user: user} do
2081 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2082 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2083 end
2084
2085 test "non unique email returns error", %{user: user} do
2086 %{email: email} = insert(:user)
2087
2088 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2089 User.change_email(user, email)
2090 end
2091
2092 test "invalid email returns error", %{user: user} do
2093 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2094 User.change_email(user, "cofe")
2095 end
2096
2097 test "changes email", %{user: user} do
2098 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2099 end
2100 end
2101
2102 describe "get_cached_by_nickname_or_id" do
2103 setup do
2104 local_user = insert(:user)
2105 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2106
2107 [local_user: local_user, remote_user: remote_user]
2108 end
2109
2110 setup do: clear_config([:instance, :limit_to_local_content])
2111
2112 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2113 remote_user: remote_user
2114 } do
2115 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2116 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2117
2118 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2119 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2120
2121 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2122 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2123 end
2124
2125 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2126 %{remote_user: remote_user} do
2127 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2128 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2129 end
2130
2131 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2132 %{remote_user: remote_user, local_user: local_user} do
2133 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2134 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2135 end
2136
2137 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2138 %{remote_user: remote_user} do
2139 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2140 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2141 end
2142
2143 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2144 %{local_user: local_user} do
2145 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2146 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2147
2148 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2149 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2150
2151 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2152 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2153 end
2154 end
2155
2156 describe "update_email_notifications/2" do
2157 setup do
2158 user = insert(:user, email_notifications: %{"digest" => true})
2159
2160 {:ok, user: user}
2161 end
2162
2163 test "Notifications are updated", %{user: user} do
2164 true = user.email_notifications["digest"]
2165 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2166 assert result.email_notifications["digest"] == false
2167 end
2168 end
2169
2170 test "avatar fallback" do
2171 user = insert(:user)
2172 assert User.avatar_url(user) =~ "/images/avi.png"
2173
2174 clear_config([:assets, :default_user_avatar], "avatar.png")
2175
2176 user = User.get_cached_by_nickname_or_id(user.nickname)
2177 assert User.avatar_url(user) =~ "avatar.png"
2178
2179 assert User.avatar_url(user, no_default: true) == nil
2180 end
2181
2182 test "get_host/1" do
2183 user = insert(:user, ap_id: "https://lain.com/users/lain", nickname: "lain")
2184 assert User.get_host(user) == "lain.com"
2185 end
2186 end