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