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