Merge develop
[akkoma] / test / user_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.UserTest do
6 alias Pleroma.Activity
7 alias Pleroma.Builders.UserBuilder
8 alias Pleroma.Object
9 alias Pleroma.Repo
10 alias Pleroma.Tests.ObanHelpers
11 alias Pleroma.User
12 alias Pleroma.Web.ActivityPub.ActivityPub
13 alias Pleroma.Web.CommonAPI
14
15 use Pleroma.DataCase
16 use Oban.Testing, repo: Pleroma.Repo
17
18 import Pleroma.Factory
19 import ExUnit.CaptureLog
20 import Swoosh.TestAssertions
21
22 setup_all do
23 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
24 :ok
25 end
26
27 setup do: clear_config([:instance, :account_activation_required])
28
29 describe "service actors" do
30 test "returns updated invisible actor" do
31 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
32 followers_uri = "#{uri}/followers"
33
34 insert(
35 :user,
36 %{
37 nickname: "relay",
38 invisible: false,
39 local: true,
40 ap_id: uri,
41 follower_address: followers_uri
42 }
43 )
44
45 actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
46 assert actor.invisible
47 end
48
49 test "returns relay user" do
50 uri = "#{Pleroma.Web.Endpoint.url()}/relay"
51 followers_uri = "#{uri}/followers"
52
53 assert %User{
54 nickname: "relay",
55 invisible: true,
56 local: true,
57 ap_id: ^uri,
58 follower_address: ^followers_uri
59 } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
60
61 assert capture_log(fn ->
62 refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
63 end) =~ "Cannot create service actor:"
64 end
65
66 test "returns invisible actor" do
67 uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
68 followers_uri = "#{uri}/followers"
69 user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
70
71 assert %User{
72 nickname: "internal.fetch-test",
73 invisible: true,
74 local: true,
75 ap_id: ^uri,
76 follower_address: ^followers_uri
77 } = user
78
79 user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
80 assert user.id == user2.id
81 end
82 end
83
84 describe "AP ID user relationships" do
85 setup do
86 {:ok, user: insert(:user)}
87 end
88
89 test "outgoing_relationships_ap_ids/1", %{user: user} do
90 rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
91
92 ap_ids_by_rel =
93 Enum.into(
94 rel_types,
95 %{},
96 fn rel_type ->
97 rel_records =
98 insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
99
100 ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
101 {rel_type, Enum.sort(ap_ids)}
102 end
103 )
104
105 assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
106 assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
107
108 assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
109 assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
110
111 assert ap_ids_by_rel[:notification_mute] ==
112 Enum.sort(User.notification_muted_users_ap_ids(user))
113
114 assert ap_ids_by_rel[:notification_mute] ==
115 Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
116
117 assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
118
119 assert ap_ids_by_rel[:reblog_mute] ==
120 Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
121
122 assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
123
124 assert ap_ids_by_rel[:inverse_subscription] ==
125 Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
126
127 outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
128
129 assert ap_ids_by_rel ==
130 Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
131 end
132 end
133
134 describe "when tags are nil" do
135 test "tagging a user" do
136 user = insert(:user, %{tags: nil})
137 user = User.tag(user, ["cool", "dude"])
138
139 assert "cool" in user.tags
140 assert "dude" in user.tags
141 end
142
143 test "untagging a user" do
144 user = insert(:user, %{tags: nil})
145 user = User.untag(user, ["cool", "dude"])
146
147 assert user.tags == []
148 end
149 end
150
151 test "ap_id returns the activity pub id for the user" do
152 user = UserBuilder.build()
153
154 expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
155
156 assert expected_ap_id == User.ap_id(user)
157 end
158
159 test "ap_followers returns the followers collection for the user" do
160 user = UserBuilder.build()
161
162 expected_followers_collection = "#{User.ap_id(user)}/followers"
163
164 assert expected_followers_collection == User.ap_followers(user)
165 end
166
167 test "ap_following returns the following collection for the user" do
168 user = UserBuilder.build()
169
170 expected_followers_collection = "#{User.ap_id(user)}/following"
171
172 assert expected_followers_collection == User.ap_following(user)
173 end
174
175 test "returns all pending follow requests" do
176 unlocked = insert(:user)
177 locked = insert(:user, locked: true)
178 follower = insert(:user)
179
180 CommonAPI.follow(follower, unlocked)
181 CommonAPI.follow(follower, locked)
182
183 assert [] = User.get_follow_requests(unlocked)
184 assert [activity] = User.get_follow_requests(locked)
185
186 assert activity
187 end
188
189 test "doesn't return already accepted or duplicate follow requests" do
190 locked = insert(:user, locked: true)
191 pending_follower = insert(:user)
192 accepted_follower = insert(:user)
193
194 CommonAPI.follow(pending_follower, locked)
195 CommonAPI.follow(pending_follower, locked)
196 CommonAPI.follow(accepted_follower, locked)
197
198 Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
199
200 assert [^pending_follower] = User.get_follow_requests(locked)
201 end
202
203 test "doesn't return follow requests for deactivated accounts" do
204 locked = insert(:user, locked: true)
205 pending_follower = insert(:user, %{deactivated: true})
206
207 CommonAPI.follow(pending_follower, locked)
208
209 assert true == pending_follower.deactivated
210 assert [] = User.get_follow_requests(locked)
211 end
212
213 test "clears follow requests when requester is blocked" do
214 followed = insert(:user, locked: true)
215 follower = insert(:user)
216
217 CommonAPI.follow(follower, followed)
218 assert [_activity] = User.get_follow_requests(followed)
219
220 {:ok, _user_relationship} = User.block(followed, follower)
221 assert [] = User.get_follow_requests(followed)
222 end
223
224 test "follow_all follows mutliple users" do
225 user = insert(:user)
226 followed_zero = insert(:user)
227 followed_one = insert(:user)
228 followed_two = insert(:user)
229 blocked = insert(:user)
230 not_followed = insert(:user)
231 reverse_blocked = insert(:user)
232
233 {:ok, _user_relationship} = User.block(user, blocked)
234 {:ok, _user_relationship} = User.block(reverse_blocked, user)
235
236 {:ok, user} = User.follow(user, followed_zero)
237
238 {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
239
240 assert User.following?(user, followed_one)
241 assert User.following?(user, followed_two)
242 assert User.following?(user, followed_zero)
243 refute User.following?(user, not_followed)
244 refute User.following?(user, blocked)
245 refute User.following?(user, reverse_blocked)
246 end
247
248 test "follow_all follows mutliple users without duplicating" do
249 user = insert(:user)
250 followed_zero = insert(:user)
251 followed_one = insert(:user)
252 followed_two = insert(:user)
253
254 {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
255 assert length(User.following(user)) == 3
256
257 {:ok, user} = User.follow_all(user, [followed_one, followed_two])
258 assert length(User.following(user)) == 4
259 end
260
261 test "follow takes a user and another user" do
262 user = insert(:user)
263 followed = insert(:user)
264
265 {:ok, user} = User.follow(user, followed)
266
267 user = User.get_cached_by_id(user.id)
268 followed = User.get_cached_by_ap_id(followed.ap_id)
269
270 assert followed.follower_count == 1
271 assert user.following_count == 1
272
273 assert User.ap_followers(followed) in User.following(user)
274 end
275
276 test "can't follow a deactivated users" do
277 user = insert(:user)
278 followed = insert(:user, %{deactivated: true})
279
280 {:error, _} = User.follow(user, followed)
281 end
282
283 test "can't follow a user who blocked us" do
284 blocker = insert(:user)
285 blockee = insert(:user)
286
287 {:ok, _user_relationship} = User.block(blocker, blockee)
288
289 {:error, _} = User.follow(blockee, blocker)
290 end
291
292 test "can't subscribe to a user who blocked us" do
293 blocker = insert(:user)
294 blocked = insert(:user)
295
296 {:ok, _user_relationship} = User.block(blocker, blocked)
297
298 {:error, _} = User.subscribe(blocked, blocker)
299 end
300
301 test "local users do not automatically follow local locked accounts" do
302 follower = insert(:user, locked: true)
303 followed = insert(:user, locked: true)
304
305 {:ok, follower} = User.maybe_direct_follow(follower, followed)
306
307 refute User.following?(follower, followed)
308 end
309
310 describe "unfollow/2" do
311 setup do: clear_config([:instance, :external_user_synchronization])
312
313 test "unfollow with syncronizes external user" do
314 Pleroma.Config.put([:instance, :external_user_synchronization], true)
315
316 followed =
317 insert(:user,
318 nickname: "fuser1",
319 follower_address: "http://localhost:4001/users/fuser1/followers",
320 following_address: "http://localhost:4001/users/fuser1/following",
321 ap_id: "http://localhost:4001/users/fuser1"
322 )
323
324 user =
325 insert(:user, %{
326 local: false,
327 nickname: "fuser2",
328 ap_id: "http://localhost:4001/users/fuser2",
329 follower_address: "http://localhost:4001/users/fuser2/followers",
330 following_address: "http://localhost:4001/users/fuser2/following"
331 })
332
333 {:ok, user} = User.follow(user, followed, :follow_accept)
334
335 {:ok, user, _activity} = User.unfollow(user, followed)
336
337 user = User.get_cached_by_id(user.id)
338
339 assert User.following(user) == []
340 end
341
342 test "unfollow takes a user and another user" do
343 followed = insert(:user)
344 user = insert(:user)
345
346 {:ok, user} = User.follow(user, followed, :follow_accept)
347
348 assert User.following(user) == [user.follower_address, followed.follower_address]
349
350 {:ok, user, _activity} = User.unfollow(user, followed)
351
352 assert User.following(user) == [user.follower_address]
353 end
354
355 test "unfollow doesn't unfollow yourself" do
356 user = insert(:user)
357
358 {:error, _} = User.unfollow(user, user)
359
360 assert User.following(user) == [user.follower_address]
361 end
362 end
363
364 test "test if a user is following another user" do
365 followed = insert(:user)
366 user = insert(:user)
367 User.follow(user, followed, :follow_accept)
368
369 assert User.following?(user, followed)
370 refute User.following?(followed, user)
371 end
372
373 test "fetches correct profile for nickname beginning with number" do
374 # Use old-style integer ID to try to reproduce the problem
375 user = insert(:user, %{id: 1080})
376 user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
377 assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
378 end
379
380 describe "user registration" do
381 @full_user_data %{
382 bio: "A guy",
383 name: "my name",
384 nickname: "nick",
385 password: "test",
386 password_confirmation: "test",
387 email: "email@example.com"
388 }
389
390 setup do: clear_config([:instance, :autofollowed_nicknames])
391 setup do: clear_config([:welcome])
392 setup do: clear_config([:instance, :account_activation_required])
393
394 test "it autofollows accounts that are set for it" do
395 user = insert(:user)
396 remote_user = insert(:user, %{local: false})
397
398 Pleroma.Config.put([:instance, :autofollowed_nicknames], [
399 user.nickname,
400 remote_user.nickname
401 ])
402
403 cng = User.register_changeset(%User{}, @full_user_data)
404
405 {:ok, registered_user} = User.register(cng)
406
407 assert User.following?(registered_user, user)
408 refute User.following?(registered_user, remote_user)
409 end
410
411 test "it sends a welcome message if it is set" do
412 welcome_user = insert(:user)
413 Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
414 Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
415 Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message")
416
417 cng = User.register_changeset(%User{}, @full_user_data)
418 {:ok, registered_user} = User.register(cng)
419 ObanHelpers.perform_all()
420
421 activity = Repo.one(Pleroma.Activity)
422 assert registered_user.ap_id in activity.recipients
423 assert Object.normalize(activity).data["content"] =~ "direct message"
424 assert activity.actor == welcome_user.ap_id
425 end
426
427 test "it sends a welcome chat message if it is set" do
428 welcome_user = insert(:user)
429 Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
430 Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
431 Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
432
433 cng = User.register_changeset(%User{}, @full_user_data)
434 {:ok, registered_user} = User.register(cng)
435 ObanHelpers.perform_all()
436
437 activity = Repo.one(Pleroma.Activity)
438 assert registered_user.ap_id in activity.recipients
439 assert Object.normalize(activity).data["content"] =~ "chat message"
440 assert activity.actor == welcome_user.ap_id
441 end
442
443 test "it sends a welcome email message if it is set" do
444 welcome_user = insert(:user)
445 Pleroma.Config.put([:welcome, :email, :enabled], true)
446 Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
447
448 Pleroma.Config.put(
449 [:welcome, :email, :subject],
450 "Hello, welcome to cool site: <%= instance_name %>"
451 )
452
453 instance_name = Pleroma.Config.get([:instance, :name])
454
455 cng = User.register_changeset(%User{}, @full_user_data)
456 {:ok, registered_user} = User.register(cng)
457 ObanHelpers.perform_all()
458
459 assert_email_sent(
460 from: {instance_name, welcome_user.email},
461 to: {registered_user.name, registered_user.email},
462 subject: "Hello, welcome to cool site: #{instance_name}",
463 html_body: "Welcome to #{instance_name}"
464 )
465 end
466
467 test "it sends a confirm email" do
468 Pleroma.Config.put([:instance, :account_activation_required], true)
469
470 cng = User.register_changeset(%User{}, @full_user_data)
471 {:ok, registered_user} = User.register(cng)
472 ObanHelpers.perform_all()
473 assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
474 end
475
476 test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
477 Pleroma.Config.put([:instance, :account_activation_required], true)
478
479 @full_user_data
480 |> Map.keys()
481 |> Enum.each(fn key ->
482 params = Map.delete(@full_user_data, key)
483 changeset = User.register_changeset(%User{}, params)
484
485 assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
486 end)
487 end
488
489 test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
490 Pleroma.Config.put([:instance, :account_activation_required], false)
491
492 @full_user_data
493 |> Map.keys()
494 |> Enum.each(fn key ->
495 params = Map.delete(@full_user_data, key)
496 changeset = User.register_changeset(%User{}, params)
497
498 assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
499 end)
500 end
501
502 test "it restricts certain nicknames" do
503 [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
504
505 assert is_bitstring(restricted_name)
506
507 params =
508 @full_user_data
509 |> Map.put(:nickname, restricted_name)
510
511 changeset = User.register_changeset(%User{}, params)
512
513 refute changeset.valid?
514 end
515
516 test "it blocks blacklisted email domains" do
517 clear_config([User, :email_blacklist], ["trolling.world"])
518
519 # Block with match
520 params = Map.put(@full_user_data, :email, "troll@trolling.world")
521 changeset = User.register_changeset(%User{}, params)
522 refute changeset.valid?
523
524 # Block with subdomain match
525 params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
526 changeset = User.register_changeset(%User{}, params)
527 refute changeset.valid?
528
529 # Pass with different domains that are similar
530 params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
531 changeset = User.register_changeset(%User{}, params)
532 assert changeset.valid?
533
534 params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
535 changeset = User.register_changeset(%User{}, params)
536 assert changeset.valid?
537 end
538
539 test "it sets the password_hash and ap_id" do
540 changeset = User.register_changeset(%User{}, @full_user_data)
541
542 assert changeset.valid?
543
544 assert is_binary(changeset.changes[:password_hash])
545 assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
546
547 assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
548 end
549
550 test "it sets the 'accepts_chat_messages' set to true" do
551 changeset = User.register_changeset(%User{}, @full_user_data)
552 assert changeset.valid?
553
554 {:ok, user} = Repo.insert(changeset)
555
556 assert user.accepts_chat_messages
557 end
558
559 test "it creates a confirmed user" do
560 changeset = User.register_changeset(%User{}, @full_user_data)
561 assert changeset.valid?
562
563 {:ok, user} = Repo.insert(changeset)
564
565 refute user.confirmation_pending
566 end
567 end
568
569 describe "user registration, with :account_activation_required" do
570 @full_user_data %{
571 bio: "A guy",
572 name: "my name",
573 nickname: "nick",
574 password: "test",
575 password_confirmation: "test",
576 email: "email@example.com"
577 }
578 setup do: clear_config([:instance, :account_activation_required], true)
579
580 test "it creates unconfirmed user" do
581 changeset = User.register_changeset(%User{}, @full_user_data)
582 assert changeset.valid?
583
584 {:ok, user} = Repo.insert(changeset)
585
586 assert user.confirmation_pending
587 assert user.confirmation_token
588 end
589
590 test "it creates confirmed user if :confirmed option is given" do
591 changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
592 assert changeset.valid?
593
594 {:ok, user} = Repo.insert(changeset)
595
596 refute user.confirmation_pending
597 refute user.confirmation_token
598 end
599 end
600
601 describe "user registration, with :account_approval_required" do
602 @full_user_data %{
603 bio: "A guy",
604 name: "my name",
605 nickname: "nick",
606 password: "test",
607 password_confirmation: "test",
608 email: "email@example.com",
609 registration_reason: "I'm a cool guy :)"
610 }
611 setup do: clear_config([:instance, :account_approval_required], true)
612
613 test "it creates unapproved user" do
614 changeset = User.register_changeset(%User{}, @full_user_data)
615 assert changeset.valid?
616
617 {:ok, user} = Repo.insert(changeset)
618
619 assert user.approval_pending
620 assert user.registration_reason == "I'm a cool guy :)"
621 end
622
623 test "it restricts length of registration reason" do
624 reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
625
626 assert is_integer(reason_limit)
627
628 params =
629 @full_user_data
630 |> Map.put(
631 :registration_reason,
632 "Quia et nesciunt dolores numquam ipsam nisi sapiente soluta. Ullam repudiandae nisi quam porro officiis officiis ad. Consequatur animi velit ex quia. Odit voluptatem perferendis quia ut nisi. Dignissimos sit soluta atque aliquid dolorem ut dolorum ut. Labore voluptates iste iusto amet voluptatum earum. Ad fugit illum nam eos ut nemo. Pariatur ea fuga non aspernatur. Dignissimos debitis officia corporis est nisi ab et. Atque itaque alias eius voluptas minus. Accusamus numquam tempore occaecati in."
633 )
634
635 changeset = User.register_changeset(%User{}, params)
636
637 refute changeset.valid?
638 end
639 end
640
641 describe "get_or_fetch/1" do
642 test "gets an existing user by nickname" do
643 user = insert(:user)
644 {:ok, fetched_user} = User.get_or_fetch(user.nickname)
645
646 assert user == fetched_user
647 end
648
649 test "gets an existing user by ap_id" do
650 ap_id = "http://mastodon.example.org/users/admin"
651
652 user =
653 insert(
654 :user,
655 local: false,
656 nickname: "admin@mastodon.example.org",
657 ap_id: ap_id
658 )
659
660 {:ok, fetched_user} = User.get_or_fetch(ap_id)
661 freshed_user = refresh_record(user)
662 assert freshed_user == fetched_user
663 end
664 end
665
666 describe "fetching a user from nickname or trying to build one" do
667 test "gets an existing user" do
668 user = insert(:user)
669 {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
670
671 assert user == fetched_user
672 end
673
674 test "gets an existing user, case insensitive" do
675 user = insert(:user, nickname: "nick")
676 {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
677
678 assert user == fetched_user
679 end
680
681 test "gets an existing user by fully qualified nickname" do
682 user = insert(:user)
683
684 {:ok, fetched_user} =
685 User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
686
687 assert user == fetched_user
688 end
689
690 test "gets an existing user by fully qualified nickname, case insensitive" do
691 user = insert(:user, nickname: "nick")
692 casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
693
694 {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
695
696 assert user == fetched_user
697 end
698
699 @tag capture_log: true
700 test "returns nil if no user could be fetched" do
701 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
702 assert fetched_user == "not found nonexistant@social.heldscal.la"
703 end
704
705 test "returns nil for nonexistant local user" do
706 {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
707 assert fetched_user == "not found nonexistant"
708 end
709
710 test "updates an existing user, if stale" do
711 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
712
713 orig_user =
714 insert(
715 :user,
716 local: false,
717 nickname: "admin@mastodon.example.org",
718 ap_id: "http://mastodon.example.org/users/admin",
719 last_refreshed_at: a_week_ago
720 )
721
722 assert orig_user.last_refreshed_at == a_week_ago
723
724 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
725
726 assert user.inbox
727
728 refute user.last_refreshed_at == orig_user.last_refreshed_at
729 end
730
731 test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
732 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
733
734 orig_user =
735 insert(
736 :user,
737 local: false,
738 nickname: "admin@mastodon.example.org",
739 ap_id: "http://mastodon.example.org/users/harinezumigari",
740 last_refreshed_at: a_week_ago
741 )
742
743 assert orig_user.last_refreshed_at == a_week_ago
744
745 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
746
747 assert user.inbox
748
749 refute user.id == orig_user.id
750
751 orig_user = User.get_by_id(orig_user.id)
752
753 assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
754 end
755
756 @tag capture_log: true
757 test "it returns the old user if stale, but unfetchable" do
758 a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
759
760 orig_user =
761 insert(
762 :user,
763 local: false,
764 nickname: "admin@mastodon.example.org",
765 ap_id: "http://mastodon.example.org/users/raymoo",
766 last_refreshed_at: a_week_ago
767 )
768
769 assert orig_user.last_refreshed_at == a_week_ago
770
771 {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
772
773 assert user.last_refreshed_at == orig_user.last_refreshed_at
774 end
775 end
776
777 test "returns an ap_id for a user" do
778 user = insert(:user)
779
780 assert User.ap_id(user) ==
781 Pleroma.Web.Router.Helpers.user_feed_url(
782 Pleroma.Web.Endpoint,
783 :feed_redirect,
784 user.nickname
785 )
786 end
787
788 test "returns an ap_followers link for a user" do
789 user = insert(:user)
790
791 assert User.ap_followers(user) ==
792 Pleroma.Web.Router.Helpers.user_feed_url(
793 Pleroma.Web.Endpoint,
794 :feed_redirect,
795 user.nickname
796 ) <> "/followers"
797 end
798
799 describe "remote user changeset" do
800 @valid_remote %{
801 bio: "hello",
802 name: "Someone",
803 nickname: "a@b.de",
804 ap_id: "http...",
805 avatar: %{some: "avatar"}
806 }
807 setup do: clear_config([:instance, :user_bio_length])
808 setup do: clear_config([:instance, :user_name_length])
809
810 test "it confirms validity" do
811 cs = User.remote_user_changeset(@valid_remote)
812 assert cs.valid?
813 end
814
815 test "it sets the follower_adress" do
816 cs = User.remote_user_changeset(@valid_remote)
817 # remote users get a fake local follower address
818 assert cs.changes.follower_address ==
819 User.ap_followers(%User{nickname: @valid_remote[:nickname]})
820 end
821
822 test "it enforces the fqn format for nicknames" do
823 cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
824 assert Ecto.Changeset.get_field(cs, :local) == false
825 assert cs.changes.avatar
826 refute cs.valid?
827 end
828
829 test "it has required fields" do
830 [:ap_id]
831 |> Enum.each(fn field ->
832 cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
833 refute cs.valid?
834 end)
835 end
836 end
837
838 describe "followers and friends" do
839 test "gets all followers for a given user" do
840 user = insert(:user)
841 follower_one = insert(:user)
842 follower_two = insert(:user)
843 not_follower = insert(:user)
844
845 {:ok, follower_one} = User.follow(follower_one, user)
846 {:ok, follower_two} = User.follow(follower_two, user)
847
848 res = User.get_followers(user)
849
850 assert Enum.member?(res, follower_one)
851 assert Enum.member?(res, follower_two)
852 refute Enum.member?(res, not_follower)
853 end
854
855 test "gets all friends (followed users) for a given user" do
856 user = insert(:user)
857 followed_one = insert(:user)
858 followed_two = insert(:user)
859 not_followed = insert(:user)
860
861 {:ok, user} = User.follow(user, followed_one)
862 {:ok, user} = User.follow(user, followed_two)
863
864 res = User.get_friends(user)
865
866 followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
867 followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
868 assert Enum.member?(res, followed_one)
869 assert Enum.member?(res, followed_two)
870 refute Enum.member?(res, not_followed)
871 end
872 end
873
874 describe "updating note and follower count" do
875 test "it sets the note_count property" do
876 note = insert(:note)
877
878 user = User.get_cached_by_ap_id(note.data["actor"])
879
880 assert user.note_count == 0
881
882 {:ok, user} = User.update_note_count(user)
883
884 assert user.note_count == 1
885 end
886
887 test "it increases the note_count property" do
888 note = insert(:note)
889 user = User.get_cached_by_ap_id(note.data["actor"])
890
891 assert user.note_count == 0
892
893 {:ok, user} = User.increase_note_count(user)
894
895 assert user.note_count == 1
896
897 {:ok, user} = User.increase_note_count(user)
898
899 assert user.note_count == 2
900 end
901
902 test "it decreases the note_count property" do
903 note = insert(:note)
904 user = User.get_cached_by_ap_id(note.data["actor"])
905
906 assert user.note_count == 0
907
908 {:ok, user} = User.increase_note_count(user)
909
910 assert user.note_count == 1
911
912 {:ok, user} = User.decrease_note_count(user)
913
914 assert user.note_count == 0
915
916 {:ok, user} = User.decrease_note_count(user)
917
918 assert user.note_count == 0
919 end
920
921 test "it sets the follower_count property" do
922 user = insert(:user)
923 follower = insert(:user)
924
925 User.follow(follower, user)
926
927 assert user.follower_count == 0
928
929 {:ok, user} = User.update_follower_count(user)
930
931 assert user.follower_count == 1
932 end
933 end
934
935 describe "follow_import" do
936 test "it imports user followings from list" do
937 [user1, user2, user3] = insert_list(3, :user)
938
939 identifiers = [
940 user2.ap_id,
941 user3.nickname
942 ]
943
944 {:ok, job} = User.follow_import(user1, identifiers)
945
946 assert {:ok, result} = ObanHelpers.perform(job)
947 assert is_list(result)
948 assert result == [user2, user3]
949 end
950 end
951
952 describe "mutes" do
953 test "it mutes people" do
954 user = insert(:user)
955 muted_user = insert(:user)
956
957 refute User.mutes?(user, muted_user)
958 refute User.muted_notifications?(user, muted_user)
959
960 {:ok, _user_relationships} = User.mute(user, muted_user)
961
962 assert User.mutes?(user, muted_user)
963 assert User.muted_notifications?(user, muted_user)
964 end
965
966 test "expiring" do
967 user = insert(:user)
968 muted_user = insert(:user)
969
970 {:ok, _user_relationships} = User.mute(user, muted_user, %{expires_in: 60})
971 assert User.mutes?(user, muted_user)
972
973 worker = Pleroma.Workers.MuteExpireWorker
974 args = %{"op" => "unmute_user", "muter_id" => user.id, "mutee_id" => muted_user.id}
975
976 assert_enqueued(
977 worker: worker,
978 args: args
979 )
980
981 assert :ok = perform_job(worker, args)
982
983 refute User.mutes?(user, muted_user)
984 refute User.muted_notifications?(user, muted_user)
985 end
986
987 test "it unmutes users" do
988 user = insert(:user)
989 muted_user = insert(:user)
990
991 {:ok, _user_relationships} = User.mute(user, muted_user)
992 {:ok, _user_mute} = User.unmute(user, muted_user)
993
994 refute User.mutes?(user, muted_user)
995 refute User.muted_notifications?(user, muted_user)
996 end
997
998 test "it mutes user without notifications" 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, %{notifications: false})
1006
1007 assert User.mutes?(user, muted_user)
1008 refute User.muted_notifications?(user, muted_user)
1009 end
1010 end
1011
1012 describe "blocks" do
1013 test "it blocks people" do
1014 user = insert(:user)
1015 blocked_user = insert(:user)
1016
1017 refute User.blocks?(user, blocked_user)
1018
1019 {:ok, _user_relationship} = User.block(user, blocked_user)
1020
1021 assert User.blocks?(user, blocked_user)
1022 end
1023
1024 test "it unblocks users" do
1025 user = insert(:user)
1026 blocked_user = insert(:user)
1027
1028 {:ok, _user_relationship} = User.block(user, blocked_user)
1029 {:ok, _user_block} = User.unblock(user, blocked_user)
1030
1031 refute User.blocks?(user, blocked_user)
1032 end
1033
1034 test "blocks tear down cyclical follow relationships" do
1035 blocker = insert(:user)
1036 blocked = insert(:user)
1037
1038 {:ok, blocker} = User.follow(blocker, blocked)
1039 {:ok, blocked} = User.follow(blocked, blocker)
1040
1041 assert User.following?(blocker, blocked)
1042 assert User.following?(blocked, blocker)
1043
1044 {:ok, _user_relationship} = User.block(blocker, blocked)
1045 blocked = User.get_cached_by_id(blocked.id)
1046
1047 assert User.blocks?(blocker, blocked)
1048
1049 refute User.following?(blocker, blocked)
1050 refute User.following?(blocked, blocker)
1051 end
1052
1053 test "blocks tear down blocker->blocked follow relationships" do
1054 blocker = insert(:user)
1055 blocked = insert(:user)
1056
1057 {:ok, blocker} = User.follow(blocker, blocked)
1058
1059 assert User.following?(blocker, blocked)
1060 refute User.following?(blocked, blocker)
1061
1062 {:ok, _user_relationship} = User.block(blocker, blocked)
1063 blocked = User.get_cached_by_id(blocked.id)
1064
1065 assert User.blocks?(blocker, blocked)
1066
1067 refute User.following?(blocker, blocked)
1068 refute User.following?(blocked, blocker)
1069 end
1070
1071 test "blocks tear down blocked->blocker follow relationships" do
1072 blocker = insert(:user)
1073 blocked = insert(:user)
1074
1075 {:ok, blocked} = User.follow(blocked, blocker)
1076
1077 refute User.following?(blocker, blocked)
1078 assert User.following?(blocked, blocker)
1079
1080 {:ok, _user_relationship} = User.block(blocker, blocked)
1081 blocked = User.get_cached_by_id(blocked.id)
1082
1083 assert User.blocks?(blocker, blocked)
1084
1085 refute User.following?(blocker, blocked)
1086 refute User.following?(blocked, blocker)
1087 end
1088
1089 test "blocks tear down blocked->blocker subscription relationships" do
1090 blocker = insert(:user)
1091 blocked = insert(:user)
1092
1093 {:ok, _subscription} = User.subscribe(blocked, blocker)
1094
1095 assert User.subscribed_to?(blocked, blocker)
1096 refute User.subscribed_to?(blocker, blocked)
1097
1098 {:ok, _user_relationship} = User.block(blocker, blocked)
1099
1100 assert User.blocks?(blocker, blocked)
1101 refute User.subscribed_to?(blocker, blocked)
1102 refute User.subscribed_to?(blocked, blocker)
1103 end
1104 end
1105
1106 describe "domain blocking" do
1107 test "blocks domains" do
1108 user = insert(:user)
1109 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1110
1111 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1112
1113 assert User.blocks?(user, collateral_user)
1114 end
1115
1116 test "does not block domain with same end" do
1117 user = insert(:user)
1118
1119 collateral_user =
1120 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1121
1122 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1123
1124 refute User.blocks?(user, collateral_user)
1125 end
1126
1127 test "does not block domain with same end if wildcard added" do
1128 user = insert(:user)
1129
1130 collateral_user =
1131 insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
1132
1133 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1134
1135 refute User.blocks?(user, collateral_user)
1136 end
1137
1138 test "blocks domain with wildcard for subdomain" do
1139 user = insert(:user)
1140
1141 user_from_subdomain =
1142 insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
1143
1144 user_with_two_subdomains =
1145 insert(:user, %{
1146 ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
1147 })
1148
1149 user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1150
1151 {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
1152
1153 assert User.blocks?(user, user_from_subdomain)
1154 assert User.blocks?(user, user_with_two_subdomains)
1155 assert User.blocks?(user, user_domain)
1156 end
1157
1158 test "unblocks domains" do
1159 user = insert(:user)
1160 collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
1161
1162 {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
1163 {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
1164
1165 refute User.blocks?(user, collateral_user)
1166 end
1167
1168 test "follows take precedence over domain blocks" do
1169 user = insert(:user)
1170 good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
1171
1172 {:ok, user} = User.block_domain(user, "meanies.social")
1173 {:ok, user} = User.follow(user, good_eggo)
1174
1175 refute User.blocks?(user, good_eggo)
1176 end
1177 end
1178
1179 describe "blocks_import" do
1180 test "it imports user blocks from list" do
1181 [user1, user2, user3] = insert_list(3, :user)
1182
1183 identifiers = [
1184 user2.ap_id,
1185 user3.nickname
1186 ]
1187
1188 {:ok, job} = User.blocks_import(user1, identifiers)
1189
1190 assert {:ok, result} = ObanHelpers.perform(job)
1191 assert is_list(result)
1192 assert result == [user2, user3]
1193 end
1194 end
1195
1196 describe "get_recipients_from_activity" do
1197 test "works for announces" do
1198 actor = insert(:user)
1199 user = insert(:user, local: true)
1200
1201 {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
1202 {:ok, announce} = CommonAPI.repeat(activity.id, user)
1203
1204 recipients = User.get_recipients_from_activity(announce)
1205
1206 assert user in recipients
1207 end
1208
1209 test "get recipients" do
1210 actor = insert(:user)
1211 user = insert(:user, local: true)
1212 user_two = insert(:user, local: false)
1213 addressed = insert(:user, local: true)
1214 addressed_remote = insert(:user, local: false)
1215
1216 {:ok, activity} =
1217 CommonAPI.post(actor, %{
1218 status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
1219 })
1220
1221 assert Enum.map([actor, addressed], & &1.ap_id) --
1222 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1223
1224 {:ok, user} = User.follow(user, actor)
1225 {:ok, _user_two} = User.follow(user_two, actor)
1226 recipients = User.get_recipients_from_activity(activity)
1227 assert length(recipients) == 3
1228 assert user in recipients
1229 assert addressed in recipients
1230 end
1231
1232 test "has following" do
1233 actor = insert(:user)
1234 user = insert(:user)
1235 user_two = insert(:user)
1236 addressed = insert(:user, local: true)
1237
1238 {:ok, activity} =
1239 CommonAPI.post(actor, %{
1240 status: "hey @#{addressed.nickname}"
1241 })
1242
1243 assert Enum.map([actor, addressed], & &1.ap_id) --
1244 Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
1245
1246 {:ok, _actor} = User.follow(actor, user)
1247 {:ok, _actor} = User.follow(actor, user_two)
1248 recipients = User.get_recipients_from_activity(activity)
1249 assert length(recipients) == 2
1250 assert addressed in recipients
1251 end
1252 end
1253
1254 describe ".deactivate" do
1255 test "can de-activate then re-activate a user" do
1256 user = insert(:user)
1257 assert false == user.deactivated
1258 {:ok, user} = User.deactivate(user)
1259 assert true == user.deactivated
1260 {:ok, user} = User.deactivate(user, false)
1261 assert false == user.deactivated
1262 end
1263
1264 test "hide a user from followers" do
1265 user = insert(:user)
1266 user2 = insert(:user)
1267
1268 {:ok, user} = User.follow(user, user2)
1269 {:ok, _user} = User.deactivate(user)
1270
1271 user2 = User.get_cached_by_id(user2.id)
1272
1273 assert user2.follower_count == 0
1274 assert [] = User.get_followers(user2)
1275 end
1276
1277 test "hide a user from friends" do
1278 user = insert(:user)
1279 user2 = insert(:user)
1280
1281 {:ok, user2} = User.follow(user2, user)
1282 assert user2.following_count == 1
1283 assert User.following_count(user2) == 1
1284
1285 {:ok, _user} = User.deactivate(user)
1286
1287 user2 = User.get_cached_by_id(user2.id)
1288
1289 assert refresh_record(user2).following_count == 0
1290 assert user2.following_count == 0
1291 assert User.following_count(user2) == 0
1292 assert [] = User.get_friends(user2)
1293 end
1294
1295 test "hide a user's statuses from timelines and notifications" do
1296 user = insert(:user)
1297 user2 = insert(:user)
1298
1299 {:ok, user2} = User.follow(user2, user)
1300
1301 {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
1302
1303 activity = Repo.preload(activity, :bookmark)
1304
1305 [notification] = Pleroma.Notification.for_user(user2)
1306 assert notification.activity.id == activity.id
1307
1308 assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
1309
1310 assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
1311 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1312 user: user2
1313 })
1314
1315 {:ok, _user} = User.deactivate(user)
1316
1317 assert [] == ActivityPub.fetch_public_activities(%{})
1318 assert [] == Pleroma.Notification.for_user(user2)
1319
1320 assert [] ==
1321 ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
1322 user: user2
1323 })
1324 end
1325 end
1326
1327 describe "approve" do
1328 test "approves a user" do
1329 user = insert(:user, approval_pending: true)
1330 assert true == user.approval_pending
1331 {:ok, user} = User.approve(user)
1332 assert false == user.approval_pending
1333 end
1334
1335 test "approves a list of users" do
1336 unapproved_users = [
1337 insert(:user, approval_pending: true),
1338 insert(:user, approval_pending: true),
1339 insert(:user, approval_pending: true)
1340 ]
1341
1342 {:ok, users} = User.approve(unapproved_users)
1343
1344 assert Enum.count(users) == 3
1345
1346 Enum.each(users, fn user ->
1347 assert false == user.approval_pending
1348 end)
1349 end
1350 end
1351
1352 describe "delete" do
1353 setup do
1354 {:ok, user} = insert(:user) |> User.set_cache()
1355
1356 [user: user]
1357 end
1358
1359 setup do: clear_config([:instance, :federating])
1360
1361 test ".delete_user_activities deletes all create activities", %{user: user} do
1362 {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
1363
1364 User.delete_user_activities(user)
1365
1366 # TODO: Test removal favorites, repeats, delete activities.
1367 refute Activity.get_by_id(activity.id)
1368 end
1369
1370 test "it deactivates a user, all follow relationships and all activities", %{user: user} do
1371 follower = insert(:user)
1372 {:ok, follower} = User.follow(follower, user)
1373
1374 locked_user = insert(:user, name: "locked", locked: true)
1375 {:ok, _} = User.follow(user, locked_user, :follow_pending)
1376
1377 object = insert(:note, user: user)
1378 activity = insert(:note_activity, user: user, note: object)
1379
1380 object_two = insert(:note, user: follower)
1381 activity_two = insert(:note_activity, user: follower, note: object_two)
1382
1383 {:ok, like} = CommonAPI.favorite(user, activity_two.id)
1384 {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
1385 {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
1386
1387 {:ok, job} = User.delete(user)
1388 {:ok, _user} = ObanHelpers.perform(job)
1389
1390 follower = User.get_cached_by_id(follower.id)
1391
1392 refute User.following?(follower, user)
1393 assert %{deactivated: true} = User.get_by_id(user.id)
1394
1395 assert [] == User.get_follow_requests(locked_user)
1396
1397 user_activities =
1398 user.ap_id
1399 |> Activity.Queries.by_actor()
1400 |> Repo.all()
1401 |> Enum.map(fn act -> act.data["type"] end)
1402
1403 assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
1404
1405 refute Activity.get_by_id(activity.id)
1406 refute Activity.get_by_id(like.id)
1407 refute Activity.get_by_id(like_two.id)
1408 refute Activity.get_by_id(repeat.id)
1409 end
1410 end
1411
1412 describe "delete/1 when confirmation is pending" do
1413 setup do
1414 user = insert(:user, confirmation_pending: true)
1415 {:ok, user: user}
1416 end
1417
1418 test "deletes user from database when activation required", %{user: user} do
1419 clear_config([:instance, :account_activation_required], true)
1420
1421 {:ok, job} = User.delete(user)
1422 {:ok, _} = ObanHelpers.perform(job)
1423
1424 refute User.get_cached_by_id(user.id)
1425 refute User.get_by_id(user.id)
1426 end
1427
1428 test "deactivates user when activation is not required", %{user: user} do
1429 clear_config([:instance, :account_activation_required], false)
1430
1431 {:ok, job} = User.delete(user)
1432 {:ok, _} = ObanHelpers.perform(job)
1433
1434 assert %{deactivated: true} = User.get_cached_by_id(user.id)
1435 assert %{deactivated: true} = User.get_by_id(user.id)
1436 end
1437 end
1438
1439 test "delete/1 when approval is pending deletes the user" do
1440 user = insert(:user, approval_pending: true)
1441
1442 {:ok, job} = User.delete(user)
1443 {:ok, _} = ObanHelpers.perform(job)
1444
1445 refute User.get_cached_by_id(user.id)
1446 refute User.get_by_id(user.id)
1447 end
1448
1449 test "delete/1 purges a user when they wouldn't be fully deleted" do
1450 user =
1451 insert(:user, %{
1452 bio: "eyy lmao",
1453 name: "qqqqqqq",
1454 password_hash: "pdfk2$1b3n159001",
1455 keys: "RSA begin buplic key",
1456 public_key: "--PRIVATE KEYE--",
1457 avatar: %{"a" => "b"},
1458 tags: ["qqqqq"],
1459 banner: %{"a" => "b"},
1460 background: %{"a" => "b"},
1461 note_count: 9,
1462 follower_count: 9,
1463 following_count: 9001,
1464 locked: true,
1465 confirmation_pending: true,
1466 password_reset_pending: true,
1467 approval_pending: true,
1468 registration_reason: "ahhhhh",
1469 confirmation_token: "qqqq",
1470 domain_blocks: ["lain.com"],
1471 deactivated: true,
1472 ap_enabled: true,
1473 is_moderator: true,
1474 is_admin: true,
1475 mastofe_settings: %{"a" => "b"},
1476 mascot: %{"a" => "b"},
1477 emoji: %{"a" => "b"},
1478 pleroma_settings_store: %{"q" => "x"},
1479 fields: [%{"gg" => "qq"}],
1480 raw_fields: [%{"gg" => "qq"}],
1481 discoverable: true,
1482 also_known_as: ["https://lol.olo/users/loll"]
1483 })
1484
1485 {:ok, job} = User.delete(user)
1486 {:ok, _} = ObanHelpers.perform(job)
1487 user = User.get_by_id(user.id)
1488
1489 assert %User{
1490 bio: "",
1491 raw_bio: nil,
1492 email: nil,
1493 name: nil,
1494 password_hash: nil,
1495 keys: nil,
1496 public_key: nil,
1497 avatar: %{},
1498 tags: [],
1499 last_refreshed_at: nil,
1500 last_digest_emailed_at: nil,
1501 banner: %{},
1502 background: %{},
1503 note_count: 0,
1504 follower_count: 0,
1505 following_count: 0,
1506 locked: false,
1507 confirmation_pending: false,
1508 password_reset_pending: false,
1509 approval_pending: false,
1510 registration_reason: nil,
1511 confirmation_token: nil,
1512 domain_blocks: [],
1513 deactivated: true,
1514 ap_enabled: false,
1515 is_moderator: false,
1516 is_admin: false,
1517 mastofe_settings: nil,
1518 mascot: nil,
1519 emoji: %{},
1520 pleroma_settings_store: %{},
1521 fields: [],
1522 raw_fields: [],
1523 discoverable: false,
1524 also_known_as: []
1525 } = user
1526 end
1527
1528 test "get_public_key_for_ap_id fetches a user that's not in the db" do
1529 assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
1530 end
1531
1532 describe "per-user rich-text filtering" do
1533 test "html_filter_policy returns default policies, when rich-text is enabled" do
1534 user = insert(:user)
1535
1536 assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
1537 end
1538
1539 test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
1540 user = insert(:user, no_rich_text: true)
1541
1542 assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
1543 end
1544 end
1545
1546 describe "caching" do
1547 test "invalidate_cache works" do
1548 user = insert(:user)
1549
1550 User.set_cache(user)
1551 User.invalidate_cache(user)
1552
1553 {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1554 {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
1555 end
1556
1557 test "User.delete() plugs any possible zombie objects" do
1558 user = insert(:user)
1559
1560 {:ok, job} = User.delete(user)
1561 {:ok, _} = ObanHelpers.perform(job)
1562
1563 {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1564
1565 assert cached_user != user
1566
1567 {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
1568
1569 assert cached_user != user
1570 end
1571 end
1572
1573 describe "account_status/1" do
1574 setup do: clear_config([:instance, :account_activation_required])
1575
1576 test "return confirmation_pending for unconfirm user" do
1577 Pleroma.Config.put([:instance, :account_activation_required], true)
1578 user = insert(:user, confirmation_pending: true)
1579 assert User.account_status(user) == :confirmation_pending
1580 end
1581
1582 test "return active for confirmed user" do
1583 Pleroma.Config.put([:instance, :account_activation_required], true)
1584 user = insert(:user, confirmation_pending: false)
1585 assert User.account_status(user) == :active
1586 end
1587
1588 test "return active for remote user" do
1589 user = insert(:user, local: false)
1590 assert User.account_status(user) == :active
1591 end
1592
1593 test "returns :password_reset_pending for user with reset password" do
1594 user = insert(:user, password_reset_pending: true)
1595 assert User.account_status(user) == :password_reset_pending
1596 end
1597
1598 test "returns :deactivated for deactivated user" do
1599 user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
1600 assert User.account_status(user) == :deactivated
1601 end
1602
1603 test "returns :approval_pending for unapproved user" do
1604 user = insert(:user, local: true, approval_pending: true)
1605 assert User.account_status(user) == :approval_pending
1606
1607 user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
1608 assert User.account_status(user) == :approval_pending
1609 end
1610 end
1611
1612 describe "superuser?/1" do
1613 test "returns false for unprivileged users" do
1614 user = insert(:user, local: true)
1615
1616 refute User.superuser?(user)
1617 end
1618
1619 test "returns false for remote users" do
1620 user = insert(:user, local: false)
1621 remote_admin_user = insert(:user, local: false, is_admin: true)
1622
1623 refute User.superuser?(user)
1624 refute User.superuser?(remote_admin_user)
1625 end
1626
1627 test "returns true for local moderators" do
1628 user = insert(:user, local: true, is_moderator: true)
1629
1630 assert User.superuser?(user)
1631 end
1632
1633 test "returns true for local admins" do
1634 user = insert(:user, local: true, is_admin: true)
1635
1636 assert User.superuser?(user)
1637 end
1638 end
1639
1640 describe "invisible?/1" do
1641 test "returns true for an invisible user" do
1642 user = insert(:user, local: true, invisible: true)
1643
1644 assert User.invisible?(user)
1645 end
1646
1647 test "returns false for a non-invisible user" do
1648 user = insert(:user, local: true)
1649
1650 refute User.invisible?(user)
1651 end
1652 end
1653
1654 describe "visible_for/2" do
1655 test "returns true when the account is itself" do
1656 user = insert(:user, local: true)
1657
1658 assert User.visible_for(user, user) == :visible
1659 end
1660
1661 test "returns false when the account is unauthenticated and auth is required" do
1662 Pleroma.Config.put([:instance, :account_activation_required], true)
1663
1664 user = insert(:user, local: true, confirmation_pending: true)
1665 other_user = insert(:user, local: true)
1666
1667 refute User.visible_for(user, other_user) == :visible
1668 end
1669
1670 test "returns true when the account is unauthenticated and auth is not required" do
1671 user = insert(:user, local: true, confirmation_pending: true)
1672 other_user = insert(:user, local: true)
1673
1674 assert User.visible_for(user, other_user) == :visible
1675 end
1676
1677 test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
1678 Pleroma.Config.put([:instance, :account_activation_required], true)
1679
1680 user = insert(:user, local: true, confirmation_pending: true)
1681 other_user = insert(:user, local: true, is_admin: true)
1682
1683 assert User.visible_for(user, other_user) == :visible
1684 end
1685 end
1686
1687 describe "parse_bio/2" do
1688 test "preserves hosts in user links text" do
1689 remote_user = insert(:user, local: false, nickname: "nick@domain.com")
1690 user = insert(:user)
1691 bio = "A.k.a. @nick@domain.com"
1692
1693 expected_text =
1694 ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
1695 remote_user.ap_id
1696 }" rel="ugc">@<span>nick@domain.com</span></a></span>)
1697
1698 assert expected_text == User.parse_bio(bio, user)
1699 end
1700
1701 test "Adds rel=me on linkbacked urls" do
1702 user = insert(:user, ap_id: "https://social.example.org/users/lain")
1703
1704 bio = "http://example.com/rel_me/null"
1705 expected_text = "<a href=\"#{bio}\">#{bio}</a>"
1706 assert expected_text == User.parse_bio(bio, user)
1707
1708 bio = "http://example.com/rel_me/link"
1709 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1710 assert expected_text == User.parse_bio(bio, user)
1711
1712 bio = "http://example.com/rel_me/anchor"
1713 expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
1714 assert expected_text == User.parse_bio(bio, user)
1715 end
1716 end
1717
1718 test "follower count is updated when a follower is blocked" do
1719 user = insert(:user)
1720 follower = insert(:user)
1721 follower2 = insert(:user)
1722 follower3 = insert(:user)
1723
1724 {:ok, follower} = User.follow(follower, user)
1725 {:ok, _follower2} = User.follow(follower2, user)
1726 {:ok, _follower3} = User.follow(follower3, user)
1727
1728 {:ok, _user_relationship} = User.block(user, follower)
1729 user = refresh_record(user)
1730
1731 assert user.follower_count == 2
1732 end
1733
1734 describe "list_inactive_users_query/1" do
1735 defp days_ago(days) do
1736 NaiveDateTime.add(
1737 NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
1738 -days * 60 * 60 * 24,
1739 :second
1740 )
1741 end
1742
1743 test "Users are inactive by default" do
1744 total = 10
1745
1746 users =
1747 Enum.map(1..total, fn _ ->
1748 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1749 end)
1750
1751 inactive_users_ids =
1752 Pleroma.User.list_inactive_users_query()
1753 |> Pleroma.Repo.all()
1754 |> Enum.map(& &1.id)
1755
1756 Enum.each(users, fn user ->
1757 assert user.id in inactive_users_ids
1758 end)
1759 end
1760
1761 test "Only includes users who has no recent activity" do
1762 total = 10
1763
1764 users =
1765 Enum.map(1..total, fn _ ->
1766 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1767 end)
1768
1769 {inactive, active} = Enum.split(users, trunc(total / 2))
1770
1771 Enum.map(active, fn user ->
1772 to = Enum.random(users -- [user])
1773
1774 {:ok, _} =
1775 CommonAPI.post(user, %{
1776 status: "hey @#{to.nickname}"
1777 })
1778 end)
1779
1780 inactive_users_ids =
1781 Pleroma.User.list_inactive_users_query()
1782 |> Pleroma.Repo.all()
1783 |> Enum.map(& &1.id)
1784
1785 Enum.each(active, fn user ->
1786 refute user.id in inactive_users_ids
1787 end)
1788
1789 Enum.each(inactive, fn user ->
1790 assert user.id in inactive_users_ids
1791 end)
1792 end
1793
1794 test "Only includes users with no read notifications" do
1795 total = 10
1796
1797 users =
1798 Enum.map(1..total, fn _ ->
1799 insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
1800 end)
1801
1802 [sender | recipients] = users
1803 {inactive, active} = Enum.split(recipients, trunc(total / 2))
1804
1805 Enum.each(recipients, fn to ->
1806 {:ok, _} =
1807 CommonAPI.post(sender, %{
1808 status: "hey @#{to.nickname}"
1809 })
1810
1811 {:ok, _} =
1812 CommonAPI.post(sender, %{
1813 status: "hey again @#{to.nickname}"
1814 })
1815 end)
1816
1817 Enum.each(active, fn user ->
1818 [n1, _n2] = Pleroma.Notification.for_user(user)
1819 {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
1820 end)
1821
1822 inactive_users_ids =
1823 Pleroma.User.list_inactive_users_query()
1824 |> Pleroma.Repo.all()
1825 |> Enum.map(& &1.id)
1826
1827 Enum.each(active, fn user ->
1828 refute user.id in inactive_users_ids
1829 end)
1830
1831 Enum.each(inactive, fn user ->
1832 assert user.id in inactive_users_ids
1833 end)
1834 end
1835 end
1836
1837 describe "toggle_confirmation/1" do
1838 test "if user is confirmed" do
1839 user = insert(:user, confirmation_pending: false)
1840 {:ok, user} = User.toggle_confirmation(user)
1841
1842 assert user.confirmation_pending
1843 assert user.confirmation_token
1844 end
1845
1846 test "if user is unconfirmed" do
1847 user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
1848 {:ok, user} = User.toggle_confirmation(user)
1849
1850 refute user.confirmation_pending
1851 refute user.confirmation_token
1852 end
1853 end
1854
1855 describe "ensure_keys_present" do
1856 test "it creates keys for a user and stores them in info" do
1857 user = insert(:user)
1858 refute is_binary(user.keys)
1859 {:ok, user} = User.ensure_keys_present(user)
1860 assert is_binary(user.keys)
1861 end
1862
1863 test "it doesn't create keys if there already are some" do
1864 user = insert(:user, keys: "xxx")
1865 {:ok, user} = User.ensure_keys_present(user)
1866 assert user.keys == "xxx"
1867 end
1868 end
1869
1870 describe "get_ap_ids_by_nicknames" do
1871 test "it returns a list of AP ids for a given set of nicknames" do
1872 user = insert(:user)
1873 user_two = insert(:user)
1874
1875 ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
1876 assert length(ap_ids) == 2
1877 assert user.ap_id in ap_ids
1878 assert user_two.ap_id in ap_ids
1879 end
1880 end
1881
1882 describe "sync followers count" do
1883 setup do
1884 user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
1885 user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
1886 insert(:user, local: true)
1887 insert(:user, local: false, deactivated: true)
1888 {:ok, user1: user1, user2: user2}
1889 end
1890
1891 test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
1892 [fdb_user1] = User.external_users(limit: 1)
1893
1894 assert fdb_user1.ap_id
1895 assert fdb_user1.ap_id == user1.ap_id
1896 assert fdb_user1.id == user1.id
1897
1898 [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
1899
1900 assert fdb_user2.ap_id
1901 assert fdb_user2.ap_id == user2.ap_id
1902 assert fdb_user2.id == user2.id
1903
1904 assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
1905 end
1906 end
1907
1908 describe "is_internal_user?/1" do
1909 test "non-internal user returns false" do
1910 user = insert(:user)
1911 refute User.is_internal_user?(user)
1912 end
1913
1914 test "user with no nickname returns true" do
1915 user = insert(:user, %{nickname: nil})
1916 assert User.is_internal_user?(user)
1917 end
1918
1919 test "user with internal-prefixed nickname returns true" do
1920 user = insert(:user, %{nickname: "internal.test"})
1921 assert User.is_internal_user?(user)
1922 end
1923 end
1924
1925 describe "update_and_set_cache/1" do
1926 test "returns error when user is stale instead Ecto.StaleEntryError" do
1927 user = insert(:user)
1928
1929 changeset = Ecto.Changeset.change(user, bio: "test")
1930
1931 Repo.delete(user)
1932
1933 assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
1934 User.update_and_set_cache(changeset)
1935 end
1936
1937 test "performs update cache if user updated" do
1938 user = insert(:user)
1939 assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1940
1941 changeset = Ecto.Changeset.change(user, bio: "test-bio")
1942
1943 assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
1944 assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
1945 assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
1946 end
1947 end
1948
1949 describe "following/followers synchronization" do
1950 setup do: clear_config([:instance, :external_user_synchronization])
1951
1952 test "updates the counters normally on following/getting a follow when disabled" do
1953 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1954 user = insert(:user)
1955
1956 other_user =
1957 insert(:user,
1958 local: false,
1959 follower_address: "http://localhost:4001/users/masto_closed/followers",
1960 following_address: "http://localhost:4001/users/masto_closed/following",
1961 ap_enabled: true
1962 )
1963
1964 assert other_user.following_count == 0
1965 assert other_user.follower_count == 0
1966
1967 {:ok, user} = Pleroma.User.follow(user, other_user)
1968 other_user = Pleroma.User.get_by_id(other_user.id)
1969
1970 assert user.following_count == 1
1971 assert other_user.follower_count == 1
1972 end
1973
1974 test "syncronizes the counters with the remote instance for the followed when enabled" do
1975 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1976
1977 user = insert(:user)
1978
1979 other_user =
1980 insert(:user,
1981 local: false,
1982 follower_address: "http://localhost:4001/users/masto_closed/followers",
1983 following_address: "http://localhost:4001/users/masto_closed/following",
1984 ap_enabled: true
1985 )
1986
1987 assert other_user.following_count == 0
1988 assert other_user.follower_count == 0
1989
1990 Pleroma.Config.put([:instance, :external_user_synchronization], true)
1991 {:ok, _user} = User.follow(user, other_user)
1992 other_user = User.get_by_id(other_user.id)
1993
1994 assert other_user.follower_count == 437
1995 end
1996
1997 test "syncronizes the counters with the remote instance for the follower when enabled" do
1998 Pleroma.Config.put([:instance, :external_user_synchronization], false)
1999
2000 user = insert(:user)
2001
2002 other_user =
2003 insert(:user,
2004 local: false,
2005 follower_address: "http://localhost:4001/users/masto_closed/followers",
2006 following_address: "http://localhost:4001/users/masto_closed/following",
2007 ap_enabled: true
2008 )
2009
2010 assert other_user.following_count == 0
2011 assert other_user.follower_count == 0
2012
2013 Pleroma.Config.put([:instance, :external_user_synchronization], true)
2014 {:ok, other_user} = User.follow(other_user, user)
2015
2016 assert other_user.following_count == 152
2017 end
2018 end
2019
2020 describe "change_email/2" do
2021 setup do
2022 [user: insert(:user)]
2023 end
2024
2025 test "blank email returns error", %{user: user} do
2026 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
2027 assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
2028 end
2029
2030 test "non unique email returns error", %{user: user} do
2031 %{email: email} = insert(:user)
2032
2033 assert {:error, %{errors: [email: {"has already been taken", _}]}} =
2034 User.change_email(user, email)
2035 end
2036
2037 test "invalid email returns error", %{user: user} do
2038 assert {:error, %{errors: [email: {"has invalid format", _}]}} =
2039 User.change_email(user, "cofe")
2040 end
2041
2042 test "changes email", %{user: user} do
2043 assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
2044 end
2045 end
2046
2047 describe "get_cached_by_nickname_or_id" do
2048 setup do
2049 local_user = insert(:user)
2050 remote_user = insert(:user, nickname: "nickname@example.com", local: false)
2051
2052 [local_user: local_user, remote_user: remote_user]
2053 end
2054
2055 setup do: clear_config([:instance, :limit_to_local_content])
2056
2057 test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
2058 remote_user: remote_user
2059 } do
2060 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2061 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2062
2063 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2064 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2065
2066 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2067 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
2068 end
2069
2070 test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
2071 %{remote_user: remote_user} do
2072 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2073 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2074 end
2075
2076 test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
2077 %{remote_user: remote_user, local_user: local_user} do
2078 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2079 assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
2080 end
2081
2082 test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
2083 %{remote_user: remote_user} do
2084 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2085 assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
2086 end
2087
2088 test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
2089 %{local_user: local_user} do
2090 Pleroma.Config.put([:instance, :limit_to_local_content], false)
2091 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2092
2093 Pleroma.Config.put([:instance, :limit_to_local_content], true)
2094 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2095
2096 Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
2097 assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
2098 end
2099 end
2100
2101 describe "update_email_notifications/2" do
2102 setup do
2103 user = insert(:user, email_notifications: %{"digest" => true})
2104
2105 {:ok, user: user}
2106 end
2107
2108 test "Notifications are updated", %{user: user} do
2109 true = user.email_notifications["digest"]
2110 assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
2111 assert result.email_notifications["digest"] == false
2112 end
2113 end
2114
2115 test "avatar fallback" do
2116 user = insert(:user)
2117 assert User.avatar_url(user) =~ "/images/avi.png"
2118
2119 clear_config([:assets, :default_user_avatar], "avatar.png")
2120
2121 user = User.get_cached_by_nickname_or_id(user.nickname)
2122 assert User.avatar_url(user) =~ "avatar.png"
2123
2124 assert User.avatar_url(user, no_default: true) == nil
2125 end
2126 end