Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2120 lines
66KB

  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. defmodule Pleroma.UserTest do
  5. alias Pleroma.Activity
  6. alias Pleroma.Builders.UserBuilder
  7. alias Pleroma.Object
  8. alias Pleroma.Repo
  9. alias Pleroma.Tests.ObanHelpers
  10. alias Pleroma.User
  11. alias Pleroma.Web.ActivityPub.ActivityPub
  12. alias Pleroma.Web.CommonAPI
  13. use Pleroma.DataCase
  14. use Oban.Testing, repo: Pleroma.Repo
  15. import Pleroma.Factory
  16. import ExUnit.CaptureLog
  17. import Swoosh.TestAssertions
  18. setup_all do
  19. Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
  20. :ok
  21. end
  22. setup do: clear_config([:instance, :account_activation_required])
  23. describe "service actors" do
  24. test "returns updated invisible actor" do
  25. uri = "#{Pleroma.Web.Endpoint.url()}/relay"
  26. followers_uri = "#{uri}/followers"
  27. insert(
  28. :user,
  29. %{
  30. nickname: "relay",
  31. invisible: false,
  32. local: true,
  33. ap_id: uri,
  34. follower_address: followers_uri
  35. }
  36. )
  37. actor = User.get_or_create_service_actor_by_ap_id(uri, "relay")
  38. assert actor.invisible
  39. end
  40. test "returns relay user" do
  41. uri = "#{Pleroma.Web.Endpoint.url()}/relay"
  42. followers_uri = "#{uri}/followers"
  43. assert %User{
  44. nickname: "relay",
  45. invisible: true,
  46. local: true,
  47. ap_id: ^uri,
  48. follower_address: ^followers_uri
  49. } = User.get_or_create_service_actor_by_ap_id(uri, "relay")
  50. assert capture_log(fn ->
  51. refute User.get_or_create_service_actor_by_ap_id("/relay", "relay")
  52. end) =~ "Cannot create service actor:"
  53. end
  54. test "returns invisible actor" do
  55. uri = "#{Pleroma.Web.Endpoint.url()}/internal/fetch-test"
  56. followers_uri = "#{uri}/followers"
  57. user = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
  58. assert %User{
  59. nickname: "internal.fetch-test",
  60. invisible: true,
  61. local: true,
  62. ap_id: ^uri,
  63. follower_address: ^followers_uri
  64. } = user
  65. user2 = User.get_or_create_service_actor_by_ap_id(uri, "internal.fetch-test")
  66. assert user.id == user2.id
  67. end
  68. end
  69. describe "AP ID user relationships" do
  70. setup do
  71. {:ok, user: insert(:user)}
  72. end
  73. test "outgoing_relationships_ap_ids/1", %{user: user} do
  74. rel_types = [:block, :mute, :notification_mute, :reblog_mute, :inverse_subscription]
  75. ap_ids_by_rel =
  76. Enum.into(
  77. rel_types,
  78. %{},
  79. fn rel_type ->
  80. rel_records =
  81. insert_list(2, :user_relationship, %{source: user, relationship_type: rel_type})
  82. ap_ids = Enum.map(rel_records, fn rr -> Repo.preload(rr, :target).target.ap_id end)
  83. {rel_type, Enum.sort(ap_ids)}
  84. end
  85. )
  86. assert ap_ids_by_rel[:block] == Enum.sort(User.blocked_users_ap_ids(user))
  87. assert ap_ids_by_rel[:block] == Enum.sort(Enum.map(User.blocked_users(user), & &1.ap_id))
  88. assert ap_ids_by_rel[:mute] == Enum.sort(User.muted_users_ap_ids(user))
  89. assert ap_ids_by_rel[:mute] == Enum.sort(Enum.map(User.muted_users(user), & &1.ap_id))
  90. assert ap_ids_by_rel[:notification_mute] ==
  91. Enum.sort(User.notification_muted_users_ap_ids(user))
  92. assert ap_ids_by_rel[:notification_mute] ==
  93. Enum.sort(Enum.map(User.notification_muted_users(user), & &1.ap_id))
  94. assert ap_ids_by_rel[:reblog_mute] == Enum.sort(User.reblog_muted_users_ap_ids(user))
  95. assert ap_ids_by_rel[:reblog_mute] ==
  96. Enum.sort(Enum.map(User.reblog_muted_users(user), & &1.ap_id))
  97. assert ap_ids_by_rel[:inverse_subscription] == Enum.sort(User.subscriber_users_ap_ids(user))
  98. assert ap_ids_by_rel[:inverse_subscription] ==
  99. Enum.sort(Enum.map(User.subscriber_users(user), & &1.ap_id))
  100. outgoing_relationships_ap_ids = User.outgoing_relationships_ap_ids(user, rel_types)
  101. assert ap_ids_by_rel ==
  102. Enum.into(outgoing_relationships_ap_ids, %{}, fn {k, v} -> {k, Enum.sort(v)} end)
  103. end
  104. end
  105. describe "when tags are nil" do
  106. test "tagging a user" do
  107. user = insert(:user, %{tags: nil})
  108. user = User.tag(user, ["cool", "dude"])
  109. assert "cool" in user.tags
  110. assert "dude" in user.tags
  111. end
  112. test "untagging a user" do
  113. user = insert(:user, %{tags: nil})
  114. user = User.untag(user, ["cool", "dude"])
  115. assert user.tags == []
  116. end
  117. end
  118. test "ap_id returns the activity pub id for the user" do
  119. user = UserBuilder.build()
  120. expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
  121. assert expected_ap_id == User.ap_id(user)
  122. end
  123. test "ap_followers returns the followers collection for the user" do
  124. user = UserBuilder.build()
  125. expected_followers_collection = "#{User.ap_id(user)}/followers"
  126. assert expected_followers_collection == User.ap_followers(user)
  127. end
  128. test "ap_following returns the following collection for the user" do
  129. user = UserBuilder.build()
  130. expected_followers_collection = "#{User.ap_id(user)}/following"
  131. assert expected_followers_collection == User.ap_following(user)
  132. end
  133. test "returns all pending follow requests" do
  134. unlocked = insert(:user)
  135. locked = insert(:user, locked: true)
  136. follower = insert(:user)
  137. CommonAPI.follow(follower, unlocked)
  138. CommonAPI.follow(follower, locked)
  139. assert [] = User.get_follow_requests(unlocked)
  140. assert [activity] = User.get_follow_requests(locked)
  141. assert activity
  142. end
  143. test "doesn't return already accepted or duplicate follow requests" do
  144. locked = insert(:user, locked: true)
  145. pending_follower = insert(:user)
  146. accepted_follower = insert(:user)
  147. CommonAPI.follow(pending_follower, locked)
  148. CommonAPI.follow(pending_follower, locked)
  149. CommonAPI.follow(accepted_follower, locked)
  150. Pleroma.FollowingRelationship.update(accepted_follower, locked, :follow_accept)
  151. assert [^pending_follower] = User.get_follow_requests(locked)
  152. end
  153. test "doesn't return follow requests for deactivated accounts" do
  154. locked = insert(:user, locked: true)
  155. pending_follower = insert(:user, %{deactivated: true})
  156. CommonAPI.follow(pending_follower, locked)
  157. assert true == pending_follower.deactivated
  158. assert [] = User.get_follow_requests(locked)
  159. end
  160. test "clears follow requests when requester is blocked" do
  161. followed = insert(:user, locked: true)
  162. follower = insert(:user)
  163. CommonAPI.follow(follower, followed)
  164. assert [_activity] = User.get_follow_requests(followed)
  165. {:ok, _user_relationship} = User.block(followed, follower)
  166. assert [] = User.get_follow_requests(followed)
  167. end
  168. test "follow_all follows mutliple users" do
  169. user = insert(:user)
  170. followed_zero = insert(:user)
  171. followed_one = insert(:user)
  172. followed_two = insert(:user)
  173. blocked = insert(:user)
  174. not_followed = insert(:user)
  175. reverse_blocked = insert(:user)
  176. {:ok, _user_relationship} = User.block(user, blocked)
  177. {:ok, _user_relationship} = User.block(reverse_blocked, user)
  178. {:ok, user} = User.follow(user, followed_zero)
  179. {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
  180. assert User.following?(user, followed_one)
  181. assert User.following?(user, followed_two)
  182. assert User.following?(user, followed_zero)
  183. refute User.following?(user, not_followed)
  184. refute User.following?(user, blocked)
  185. refute User.following?(user, reverse_blocked)
  186. end
  187. test "follow_all follows mutliple users without duplicating" do
  188. user = insert(:user)
  189. followed_zero = insert(:user)
  190. followed_one = insert(:user)
  191. followed_two = insert(:user)
  192. {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
  193. assert length(User.following(user)) == 3
  194. {:ok, user} = User.follow_all(user, [followed_one, followed_two])
  195. assert length(User.following(user)) == 4
  196. end
  197. test "follow takes a user and another user" do
  198. user = insert(:user)
  199. followed = insert(:user)
  200. {:ok, user} = User.follow(user, followed)
  201. user = User.get_cached_by_id(user.id)
  202. followed = User.get_cached_by_ap_id(followed.ap_id)
  203. assert followed.follower_count == 1
  204. assert user.following_count == 1
  205. assert User.ap_followers(followed) in User.following(user)
  206. end
  207. test "can't follow a deactivated users" do
  208. user = insert(:user)
  209. followed = insert(:user, %{deactivated: true})
  210. {:error, _} = User.follow(user, followed)
  211. end
  212. test "can't follow a user who blocked us" do
  213. blocker = insert(:user)
  214. blockee = insert(:user)
  215. {:ok, _user_relationship} = User.block(blocker, blockee)
  216. {:error, _} = User.follow(blockee, blocker)
  217. end
  218. test "can't subscribe to a user who blocked us" do
  219. blocker = insert(:user)
  220. blocked = insert(:user)
  221. {:ok, _user_relationship} = User.block(blocker, blocked)
  222. {:error, _} = User.subscribe(blocked, blocker)
  223. end
  224. test "local users do not automatically follow local locked accounts" do
  225. follower = insert(:user, locked: true)
  226. followed = insert(:user, locked: true)
  227. {:ok, follower} = User.maybe_direct_follow(follower, followed)
  228. refute User.following?(follower, followed)
  229. end
  230. describe "unfollow/2" do
  231. setup do: clear_config([:instance, :external_user_synchronization])
  232. test "unfollow with syncronizes external user" do
  233. Pleroma.Config.put([:instance, :external_user_synchronization], true)
  234. followed =
  235. insert(:user,
  236. nickname: "fuser1",
  237. follower_address: "http://localhost:4001/users/fuser1/followers",
  238. following_address: "http://localhost:4001/users/fuser1/following",
  239. ap_id: "http://localhost:4001/users/fuser1"
  240. )
  241. user =
  242. insert(:user, %{
  243. local: false,
  244. nickname: "fuser2",
  245. ap_id: "http://localhost:4001/users/fuser2",
  246. follower_address: "http://localhost:4001/users/fuser2/followers",
  247. following_address: "http://localhost:4001/users/fuser2/following"
  248. })
  249. {:ok, user} = User.follow(user, followed, :follow_accept)
  250. {:ok, user, _activity} = User.unfollow(user, followed)
  251. user = User.get_cached_by_id(user.id)
  252. assert User.following(user) == []
  253. end
  254. test "unfollow takes a user and another user" do
  255. followed = insert(:user)
  256. user = insert(:user)
  257. {:ok, user} = User.follow(user, followed, :follow_accept)
  258. assert User.following(user) == [user.follower_address, followed.follower_address]
  259. {:ok, user, _activity} = User.unfollow(user, followed)
  260. assert User.following(user) == [user.follower_address]
  261. end
  262. test "unfollow doesn't unfollow yourself" do
  263. user = insert(:user)
  264. {:error, _} = User.unfollow(user, user)
  265. assert User.following(user) == [user.follower_address]
  266. end
  267. end
  268. test "test if a user is following another user" do
  269. followed = insert(:user)
  270. user = insert(:user)
  271. User.follow(user, followed, :follow_accept)
  272. assert User.following?(user, followed)
  273. refute User.following?(followed, user)
  274. end
  275. test "fetches correct profile for nickname beginning with number" do
  276. # Use old-style integer ID to try to reproduce the problem
  277. user = insert(:user, %{id: 1080})
  278. user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
  279. assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
  280. end
  281. describe "user registration" do
  282. @full_user_data %{
  283. bio: "A guy",
  284. name: "my name",
  285. nickname: "nick",
  286. password: "test",
  287. password_confirmation: "test",
  288. email: "email@example.com"
  289. }
  290. setup do: clear_config([:instance, :autofollowed_nicknames])
  291. setup do: clear_config([:welcome])
  292. setup do: clear_config([:instance, :account_activation_required])
  293. test "it autofollows accounts that are set for it" do
  294. user = insert(:user)
  295. remote_user = insert(:user, %{local: false})
  296. Pleroma.Config.put([:instance, :autofollowed_nicknames], [
  297. user.nickname,
  298. remote_user.nickname
  299. ])
  300. cng = User.register_changeset(%User{}, @full_user_data)
  301. {:ok, registered_user} = User.register(cng)
  302. assert User.following?(registered_user, user)
  303. refute User.following?(registered_user, remote_user)
  304. end
  305. test "it sends a welcome message if it is set" do
  306. welcome_user = insert(:user)
  307. Pleroma.Config.put([:welcome, :direct_message, :enabled], true)
  308. Pleroma.Config.put([:welcome, :direct_message, :sender_nickname], welcome_user.nickname)
  309. Pleroma.Config.put([:welcome, :direct_message, :message], "Hello, this is a direct message")
  310. cng = User.register_changeset(%User{}, @full_user_data)
  311. {:ok, registered_user} = User.register(cng)
  312. ObanHelpers.perform_all()
  313. activity = Repo.one(Pleroma.Activity)
  314. assert registered_user.ap_id in activity.recipients
  315. assert Object.normalize(activity).data["content"] =~ "direct message"
  316. assert activity.actor == welcome_user.ap_id
  317. end
  318. test "it sends a welcome chat message if it is set" do
  319. welcome_user = insert(:user)
  320. Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
  321. Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
  322. Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
  323. cng = User.register_changeset(%User{}, @full_user_data)
  324. {:ok, registered_user} = User.register(cng)
  325. ObanHelpers.perform_all()
  326. activity = Repo.one(Pleroma.Activity)
  327. assert registered_user.ap_id in activity.recipients
  328. assert Object.normalize(activity).data["content"] =~ "chat message"
  329. assert activity.actor == welcome_user.ap_id
  330. end
  331. setup do:
  332. clear_config(:mrf_simple,
  333. media_removal: [],
  334. media_nsfw: [],
  335. federated_timeline_removal: [],
  336. report_removal: [],
  337. reject: [],
  338. followers_only: [],
  339. accept: [],
  340. avatar_removal: [],
  341. banner_removal: [],
  342. reject_deletes: []
  343. )
  344. setup do:
  345. clear_config(:mrf,
  346. policies: [
  347. Pleroma.Web.ActivityPub.MRF.SimplePolicy
  348. ]
  349. )
  350. test "it sends a welcome chat message when Simple policy applied to local instance" do
  351. Pleroma.Config.put([:mrf_simple, :media_nsfw], ["localhost"])
  352. welcome_user = insert(:user)
  353. Pleroma.Config.put([:welcome, :chat_message, :enabled], true)
  354. Pleroma.Config.put([:welcome, :chat_message, :sender_nickname], welcome_user.nickname)
  355. Pleroma.Config.put([:welcome, :chat_message, :message], "Hello, this is a chat message")
  356. cng = User.register_changeset(%User{}, @full_user_data)
  357. {:ok, registered_user} = User.register(cng)
  358. ObanHelpers.perform_all()
  359. activity = Repo.one(Pleroma.Activity)
  360. assert registered_user.ap_id in activity.recipients
  361. assert Object.normalize(activity).data["content"] =~ "chat message"
  362. assert activity.actor == welcome_user.ap_id
  363. end
  364. test "it sends a welcome email message if it is set" do
  365. welcome_user = insert(:user)
  366. Pleroma.Config.put([:welcome, :email, :enabled], true)
  367. Pleroma.Config.put([:welcome, :email, :sender], welcome_user.email)
  368. Pleroma.Config.put(
  369. [:welcome, :email, :subject],
  370. "Hello, welcome to cool site: <%= instance_name %>"
  371. )
  372. instance_name = Pleroma.Config.get([:instance, :name])
  373. cng = User.register_changeset(%User{}, @full_user_data)
  374. {:ok, registered_user} = User.register(cng)
  375. ObanHelpers.perform_all()
  376. assert_email_sent(
  377. from: {instance_name, welcome_user.email},
  378. to: {registered_user.name, registered_user.email},
  379. subject: "Hello, welcome to cool site: #{instance_name}",
  380. html_body: "Welcome to #{instance_name}"
  381. )
  382. end
  383. test "it sends a confirm email" do
  384. Pleroma.Config.put([:instance, :account_activation_required], true)
  385. cng = User.register_changeset(%User{}, @full_user_data)
  386. {:ok, registered_user} = User.register(cng)
  387. ObanHelpers.perform_all()
  388. assert_email_sent(Pleroma.Emails.UserEmail.account_confirmation_email(registered_user))
  389. end
  390. test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
  391. Pleroma.Config.put([:instance, :account_activation_required], true)
  392. @full_user_data
  393. |> Map.keys()
  394. |> Enum.each(fn key ->
  395. params = Map.delete(@full_user_data, key)
  396. changeset = User.register_changeset(%User{}, params)
  397. assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
  398. end)
  399. end
  400. test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
  401. Pleroma.Config.put([:instance, :account_activation_required], false)
  402. @full_user_data
  403. |> Map.keys()
  404. |> Enum.each(fn key ->
  405. params = Map.delete(@full_user_data, key)
  406. changeset = User.register_changeset(%User{}, params)
  407. assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
  408. end)
  409. end
  410. test "it restricts certain nicknames" do
  411. [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
  412. assert is_bitstring(restricted_name)
  413. params =
  414. @full_user_data
  415. |> Map.put(:nickname, restricted_name)
  416. changeset = User.register_changeset(%User{}, params)
  417. refute changeset.valid?
  418. end
  419. test "it blocks blacklisted email domains" do
  420. clear_config([User, :email_blacklist], ["trolling.world"])
  421. # Block with match
  422. params = Map.put(@full_user_data, :email, "troll@trolling.world")
  423. changeset = User.register_changeset(%User{}, params)
  424. refute changeset.valid?
  425. # Block with subdomain match
  426. params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
  427. changeset = User.register_changeset(%User{}, params)
  428. refute changeset.valid?
  429. # Pass with different domains that are similar
  430. params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
  431. changeset = User.register_changeset(%User{}, params)
  432. assert changeset.valid?
  433. params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
  434. changeset = User.register_changeset(%User{}, params)
  435. assert changeset.valid?
  436. end
  437. test "it sets the password_hash and ap_id" do
  438. changeset = User.register_changeset(%User{}, @full_user_data)
  439. assert changeset.valid?
  440. assert is_binary(changeset.changes[:password_hash])
  441. assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
  442. assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
  443. end
  444. test "it sets the 'accepts_chat_messages' set to true" do
  445. changeset = User.register_changeset(%User{}, @full_user_data)
  446. assert changeset.valid?
  447. {:ok, user} = Repo.insert(changeset)
  448. assert user.accepts_chat_messages
  449. end
  450. test "it creates a confirmed user" do
  451. changeset = User.register_changeset(%User{}, @full_user_data)
  452. assert changeset.valid?
  453. {:ok, user} = Repo.insert(changeset)
  454. refute user.confirmation_pending
  455. end
  456. end
  457. describe "user registration, with :account_activation_required" do
  458. @full_user_data %{
  459. bio: "A guy",
  460. name: "my name",
  461. nickname: "nick",
  462. password: "test",
  463. password_confirmation: "test",
  464. email: "email@example.com"
  465. }
  466. setup do: clear_config([:instance, :account_activation_required], true)
  467. test "it creates unconfirmed user" do
  468. changeset = User.register_changeset(%User{}, @full_user_data)
  469. assert changeset.valid?
  470. {:ok, user} = Repo.insert(changeset)
  471. assert user.confirmation_pending
  472. assert user.confirmation_token
  473. end
  474. test "it creates confirmed user if :confirmed option is given" do
  475. changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
  476. assert changeset.valid?
  477. {:ok, user} = Repo.insert(changeset)
  478. refute user.confirmation_pending
  479. refute user.confirmation_token
  480. end
  481. end
  482. describe "user registration, with :account_approval_required" do
  483. @full_user_data %{
  484. bio: "A guy",
  485. name: "my name",
  486. nickname: "nick",
  487. password: "test",
  488. password_confirmation: "test",
  489. email: "email@example.com",
  490. registration_reason: "I'm a cool guy :)"
  491. }
  492. setup do: clear_config([:instance, :account_approval_required], true)
  493. test "it creates unapproved user" do
  494. changeset = User.register_changeset(%User{}, @full_user_data)
  495. assert changeset.valid?
  496. {:ok, user} = Repo.insert(changeset)
  497. assert user.approval_pending
  498. assert user.registration_reason == "I'm a cool guy :)"
  499. end
  500. test "it restricts length of registration reason" do
  501. reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
  502. assert is_integer(reason_limit)
  503. params =
  504. @full_user_data
  505. |> Map.put(
  506. :registration_reason,
  507. "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."
  508. )
  509. changeset = User.register_changeset(%User{}, params)
  510. refute changeset.valid?
  511. end
  512. end
  513. describe "get_or_fetch/1" do
  514. test "gets an existing user by nickname" do
  515. user = insert(:user)
  516. {:ok, fetched_user} = User.get_or_fetch(user.nickname)
  517. assert user == fetched_user
  518. end
  519. test "gets an existing user by ap_id" do
  520. ap_id = "http://mastodon.example.org/users/admin"
  521. user =
  522. insert(
  523. :user,
  524. local: false,
  525. nickname: "admin@mastodon.example.org",
  526. ap_id: ap_id
  527. )
  528. {:ok, fetched_user} = User.get_or_fetch(ap_id)
  529. freshed_user = refresh_record(user)
  530. assert freshed_user == fetched_user
  531. end
  532. end
  533. describe "fetching a user from nickname or trying to build one" do
  534. test "gets an existing user" do
  535. user = insert(:user)
  536. {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
  537. assert user == fetched_user
  538. end
  539. test "gets an existing user, case insensitive" do
  540. user = insert(:user, nickname: "nick")
  541. {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
  542. assert user == fetched_user
  543. end
  544. test "gets an existing user by fully qualified nickname" do
  545. user = insert(:user)
  546. {:ok, fetched_user} =
  547. User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
  548. assert user == fetched_user
  549. end
  550. test "gets an existing user by fully qualified nickname, case insensitive" do
  551. user = insert(:user, nickname: "nick")
  552. casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
  553. {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
  554. assert user == fetched_user
  555. end
  556. @tag capture_log: true
  557. test "returns nil if no user could be fetched" do
  558. {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
  559. assert fetched_user == "not found nonexistant@social.heldscal.la"
  560. end
  561. test "returns nil for nonexistant local user" do
  562. {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
  563. assert fetched_user == "not found nonexistant"
  564. end
  565. test "updates an existing user, if stale" do
  566. a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
  567. orig_user =
  568. insert(
  569. :user,
  570. local: false,
  571. nickname: "admin@mastodon.example.org",
  572. ap_id: "http://mastodon.example.org/users/admin",
  573. last_refreshed_at: a_week_ago
  574. )
  575. assert orig_user.last_refreshed_at == a_week_ago
  576. {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
  577. assert user.inbox
  578. refute user.last_refreshed_at == orig_user.last_refreshed_at
  579. end
  580. test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
  581. a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
  582. orig_user =
  583. insert(
  584. :user,
  585. local: false,
  586. nickname: "admin@mastodon.example.org",
  587. ap_id: "http://mastodon.example.org/users/harinezumigari",
  588. last_refreshed_at: a_week_ago
  589. )
  590. assert orig_user.last_refreshed_at == a_week_ago
  591. {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
  592. assert user.inbox
  593. refute user.id == orig_user.id
  594. orig_user = User.get_by_id(orig_user.id)
  595. assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
  596. end
  597. @tag capture_log: true
  598. test "it returns the old user if stale, but unfetchable" do
  599. a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
  600. orig_user =
  601. insert(
  602. :user,
  603. local: false,
  604. nickname: "admin@mastodon.example.org",
  605. ap_id: "http://mastodon.example.org/users/raymoo",
  606. last_refreshed_at: a_week_ago
  607. )
  608. assert orig_user.last_refreshed_at == a_week_ago
  609. {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
  610. assert user.last_refreshed_at == orig_user.last_refreshed_at
  611. end
  612. end
  613. test "returns an ap_id for a user" do
  614. user = insert(:user)
  615. assert User.ap_id(user) ==
  616. Pleroma.Web.Router.Helpers.user_feed_url(
  617. Pleroma.Web.Endpoint,
  618. :feed_redirect,
  619. user.nickname
  620. )
  621. end
  622. test "returns an ap_followers link for a user" do
  623. user = insert(:user)
  624. assert User.ap_followers(user) ==
  625. Pleroma.Web.Router.Helpers.user_feed_url(
  626. Pleroma.Web.Endpoint,
  627. :feed_redirect,
  628. user.nickname
  629. ) <> "/followers"
  630. end
  631. describe "remote user changeset" do
  632. @valid_remote %{
  633. bio: "hello",
  634. name: "Someone",
  635. nickname: "a@b.de",
  636. ap_id: "http...",
  637. avatar: %{some: "avatar"}
  638. }
  639. setup do: clear_config([:instance, :user_bio_length])
  640. setup do: clear_config([:instance, :user_name_length])
  641. test "it confirms validity" do
  642. cs = User.remote_user_changeset(@valid_remote)
  643. assert cs.valid?
  644. end
  645. test "it sets the follower_adress" do
  646. cs = User.remote_user_changeset(@valid_remote)
  647. # remote users get a fake local follower address
  648. assert cs.changes.follower_address ==
  649. User.ap_followers(%User{nickname: @valid_remote[:nickname]})
  650. end
  651. test "it enforces the fqn format for nicknames" do
  652. cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
  653. assert Ecto.Changeset.get_field(cs, :local) == false
  654. assert cs.changes.avatar
  655. refute cs.valid?
  656. end
  657. test "it has required fields" do
  658. [:ap_id]
  659. |> Enum.each(fn field ->
  660. cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
  661. refute cs.valid?
  662. end)
  663. end
  664. end
  665. describe "followers and friends" do
  666. test "gets all followers for a given user" do
  667. user = insert(:user)
  668. follower_one = insert(:user)
  669. follower_two = insert(:user)
  670. not_follower = insert(:user)
  671. {:ok, follower_one} = User.follow(follower_one, user)
  672. {:ok, follower_two} = User.follow(follower_two, user)
  673. res = User.get_followers(user)
  674. assert Enum.member?(res, follower_one)
  675. assert Enum.member?(res, follower_two)
  676. refute Enum.member?(res, not_follower)
  677. end
  678. test "gets all friends (followed users) for a given user" do
  679. user = insert(:user)
  680. followed_one = insert(:user)
  681. followed_two = insert(:user)
  682. not_followed = insert(:user)
  683. {:ok, user} = User.follow(user, followed_one)
  684. {:ok, user} = User.follow(user, followed_two)
  685. res = User.get_friends(user)
  686. followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
  687. followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
  688. assert Enum.member?(res, followed_one)
  689. assert Enum.member?(res, followed_two)
  690. refute Enum.member?(res, not_followed)
  691. end
  692. end
  693. describe "updating note and follower count" do
  694. test "it sets the note_count property" do
  695. note = insert(:note)
  696. user = User.get_cached_by_ap_id(note.data["actor"])
  697. assert user.note_count == 0
  698. {:ok, user} = User.update_note_count(user)
  699. assert user.note_count == 1
  700. end
  701. test "it increases the note_count property" do
  702. note = insert(:note)
  703. user = User.get_cached_by_ap_id(note.data["actor"])
  704. assert user.note_count == 0
  705. {:ok, user} = User.increase_note_count(user)
  706. assert user.note_count == 1
  707. {:ok, user} = User.increase_note_count(user)
  708. assert user.note_count == 2
  709. end
  710. test "it decreases the note_count property" do
  711. note = insert(:note)
  712. user = User.get_cached_by_ap_id(note.data["actor"])
  713. assert user.note_count == 0
  714. {:ok, user} = User.increase_note_count(user)
  715. assert user.note_count == 1
  716. {:ok, user} = User.decrease_note_count(user)
  717. assert user.note_count == 0
  718. {:ok, user} = User.decrease_note_count(user)
  719. assert user.note_count == 0
  720. end
  721. test "it sets the follower_count property" do
  722. user = insert(:user)
  723. follower = insert(:user)
  724. User.follow(follower, user)
  725. assert user.follower_count == 0
  726. {:ok, user} = User.update_follower_count(user)
  727. assert user.follower_count == 1
  728. end
  729. end
  730. describe "mutes" do
  731. test "it mutes people" do
  732. user = insert(:user)
  733. muted_user = insert(:user)
  734. refute User.mutes?(user, muted_user)
  735. refute User.muted_notifications?(user, muted_user)
  736. {:ok, _user_relationships} = User.mute(user, muted_user)
  737. assert User.mutes?(user, muted_user)
  738. assert User.muted_notifications?(user, muted_user)
  739. end
  740. test "it unmutes users" do
  741. user = insert(:user)
  742. muted_user = insert(:user)
  743. {:ok, _user_relationships} = User.mute(user, muted_user)
  744. {:ok, _user_mute} = User.unmute(user, muted_user)
  745. refute User.mutes?(user, muted_user)
  746. refute User.muted_notifications?(user, muted_user)
  747. end
  748. test "it mutes user without notifications" do
  749. user = insert(:user)
  750. muted_user = insert(:user)
  751. refute User.mutes?(user, muted_user)
  752. refute User.muted_notifications?(user, muted_user)
  753. {:ok, _user_relationships} = User.mute(user, muted_user, false)
  754. assert User.mutes?(user, muted_user)
  755. refute User.muted_notifications?(user, muted_user)
  756. end
  757. end
  758. describe "blocks" do
  759. test "it blocks people" do
  760. user = insert(:user)
  761. blocked_user = insert(:user)
  762. refute User.blocks?(user, blocked_user)
  763. {:ok, _user_relationship} = User.block(user, blocked_user)
  764. assert User.blocks?(user, blocked_user)
  765. end
  766. test "it unblocks users" do
  767. user = insert(:user)
  768. blocked_user = insert(:user)
  769. {:ok, _user_relationship} = User.block(user, blocked_user)
  770. {:ok, _user_block} = User.unblock(user, blocked_user)
  771. refute User.blocks?(user, blocked_user)
  772. end
  773. test "blocks tear down cyclical follow relationships" do
  774. blocker = insert(:user)
  775. blocked = insert(:user)
  776. {:ok, blocker} = User.follow(blocker, blocked)
  777. {:ok, blocked} = User.follow(blocked, blocker)
  778. assert User.following?(blocker, blocked)
  779. assert User.following?(blocked, blocker)
  780. {:ok, _user_relationship} = User.block(blocker, blocked)
  781. blocked = User.get_cached_by_id(blocked.id)
  782. assert User.blocks?(blocker, blocked)
  783. refute User.following?(blocker, blocked)
  784. refute User.following?(blocked, blocker)
  785. end
  786. test "blocks tear down blocker->blocked follow relationships" do
  787. blocker = insert(:user)
  788. blocked = insert(:user)
  789. {:ok, blocker} = User.follow(blocker, blocked)
  790. assert User.following?(blocker, blocked)
  791. refute User.following?(blocked, blocker)
  792. {:ok, _user_relationship} = User.block(blocker, blocked)
  793. blocked = User.get_cached_by_id(blocked.id)
  794. assert User.blocks?(blocker, blocked)
  795. refute User.following?(blocker, blocked)
  796. refute User.following?(blocked, blocker)
  797. end
  798. test "blocks tear down blocked->blocker follow relationships" do
  799. blocker = insert(:user)
  800. blocked = insert(:user)
  801. {:ok, blocked} = User.follow(blocked, blocker)
  802. refute User.following?(blocker, blocked)
  803. assert User.following?(blocked, blocker)
  804. {:ok, _user_relationship} = User.block(blocker, blocked)
  805. blocked = User.get_cached_by_id(blocked.id)
  806. assert User.blocks?(blocker, blocked)
  807. refute User.following?(blocker, blocked)
  808. refute User.following?(blocked, blocker)
  809. end
  810. test "blocks tear down blocked->blocker subscription relationships" do
  811. blocker = insert(:user)
  812. blocked = insert(:user)
  813. {:ok, _subscription} = User.subscribe(blocked, blocker)
  814. assert User.subscribed_to?(blocked, blocker)
  815. refute User.subscribed_to?(blocker, blocked)
  816. {:ok, _user_relationship} = User.block(blocker, blocked)
  817. assert User.blocks?(blocker, blocked)
  818. refute User.subscribed_to?(blocker, blocked)
  819. refute User.subscribed_to?(blocked, blocker)
  820. end
  821. end
  822. describe "domain blocking" do
  823. test "blocks domains" do
  824. user = insert(:user)
  825. collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  826. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  827. assert User.blocks?(user, collateral_user)
  828. end
  829. test "does not block domain with same end" do
  830. user = insert(:user)
  831. collateral_user =
  832. insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
  833. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  834. refute User.blocks?(user, collateral_user)
  835. end
  836. test "does not block domain with same end if wildcard added" do
  837. user = insert(:user)
  838. collateral_user =
  839. insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
  840. {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
  841. refute User.blocks?(user, collateral_user)
  842. end
  843. test "blocks domain with wildcard for subdomain" do
  844. user = insert(:user)
  845. user_from_subdomain =
  846. insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
  847. user_with_two_subdomains =
  848. insert(:user, %{
  849. ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
  850. })
  851. user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  852. {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
  853. assert User.blocks?(user, user_from_subdomain)
  854. assert User.blocks?(user, user_with_two_subdomains)
  855. assert User.blocks?(user, user_domain)
  856. end
  857. test "unblocks domains" do
  858. user = insert(:user)
  859. collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  860. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  861. {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
  862. refute User.blocks?(user, collateral_user)
  863. end
  864. test "follows take precedence over domain blocks" do
  865. user = insert(:user)
  866. good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
  867. {:ok, user} = User.block_domain(user, "meanies.social")
  868. {:ok, user} = User.follow(user, good_eggo)
  869. refute User.blocks?(user, good_eggo)
  870. end
  871. end
  872. describe "get_recipients_from_activity" do
  873. test "works for announces" do
  874. actor = insert(:user)
  875. user = insert(:user, local: true)
  876. {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
  877. {:ok, announce} = CommonAPI.repeat(activity.id, user)
  878. recipients = User.get_recipients_from_activity(announce)
  879. assert user in recipients
  880. end
  881. test "get recipients" do
  882. actor = insert(:user)
  883. user = insert(:user, local: true)
  884. user_two = insert(:user, local: false)
  885. addressed = insert(:user, local: true)
  886. addressed_remote = insert(:user, local: false)
  887. {:ok, activity} =
  888. CommonAPI.post(actor, %{
  889. status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
  890. })
  891. assert Enum.map([actor, addressed], & &1.ap_id) --
  892. Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
  893. {:ok, user} = User.follow(user, actor)
  894. {:ok, _user_two} = User.follow(user_two, actor)
  895. recipients = User.get_recipients_from_activity(activity)
  896. assert length(recipients) == 3
  897. assert user in recipients
  898. assert addressed in recipients
  899. end
  900. test "has following" do
  901. actor = insert(:user)
  902. user = insert(:user)
  903. user_two = insert(:user)
  904. addressed = insert(:user, local: true)
  905. {:ok, activity} =
  906. CommonAPI.post(actor, %{
  907. status: "hey @#{addressed.nickname}"
  908. })
  909. assert Enum.map([actor, addressed], & &1.ap_id) --
  910. Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
  911. {:ok, _actor} = User.follow(actor, user)
  912. {:ok, _actor} = User.follow(actor, user_two)
  913. recipients = User.get_recipients_from_activity(activity)
  914. assert length(recipients) == 2
  915. assert addressed in recipients
  916. end
  917. end
  918. describe ".deactivate" do
  919. test "can de-activate then re-activate a user" do
  920. user = insert(:user)
  921. assert false == user.deactivated
  922. {:ok, user} = User.deactivate(user)
  923. assert true == user.deactivated
  924. {:ok, user} = User.deactivate(user, false)
  925. assert false == user.deactivated
  926. end
  927. test "hide a user from followers" do
  928. user = insert(:user)
  929. user2 = insert(:user)
  930. {:ok, user} = User.follow(user, user2)
  931. {:ok, _user} = User.deactivate(user)
  932. user2 = User.get_cached_by_id(user2.id)
  933. assert user2.follower_count == 0
  934. assert [] = User.get_followers(user2)
  935. end
  936. test "hide a user from friends" do
  937. user = insert(:user)
  938. user2 = insert(:user)
  939. {:ok, user2} = User.follow(user2, user)
  940. assert user2.following_count == 1
  941. assert User.following_count(user2) == 1
  942. {:ok, _user} = User.deactivate(user)
  943. user2 = User.get_cached_by_id(user2.id)
  944. assert refresh_record(user2).following_count == 0
  945. assert user2.following_count == 0
  946. assert User.following_count(user2) == 0
  947. assert [] = User.get_friends(user2)
  948. end
  949. test "hide a user's statuses from timelines and notifications" do
  950. user = insert(:user)
  951. user2 = insert(:user)
  952. {:ok, user2} = User.follow(user2, user)
  953. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
  954. activity = Repo.preload(activity, :bookmark)
  955. [notification] = Pleroma.Notification.for_user(user2)
  956. assert notification.activity.id == activity.id
  957. assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
  958. assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
  959. ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
  960. user: user2
  961. })
  962. {:ok, _user} = User.deactivate(user)
  963. assert [] == ActivityPub.fetch_public_activities(%{})
  964. assert [] == Pleroma.Notification.for_user(user2)
  965. assert [] ==
  966. ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
  967. user: user2
  968. })
  969. end
  970. end
  971. describe "approve" do
  972. test "approves a user" do
  973. user = insert(:user, approval_pending: true)
  974. assert true == user.approval_pending
  975. {:ok, user} = User.approve(user)
  976. assert false == user.approval_pending
  977. end
  978. test "approves a list of users" do
  979. unapproved_users = [
  980. insert(:user, approval_pending: true),
  981. insert(:user, approval_pending: true),
  982. insert(:user, approval_pending: true)
  983. ]
  984. {:ok, users} = User.approve(unapproved_users)
  985. assert Enum.count(users) == 3
  986. Enum.each(users, fn user ->
  987. assert false == user.approval_pending
  988. end)
  989. end
  990. end
  991. describe "delete" do
  992. setup do
  993. {:ok, user} = insert(:user) |> User.set_cache()
  994. [user: user]
  995. end
  996. setup do: clear_config([:instance, :federating])
  997. test ".delete_user_activities deletes all create activities", %{user: user} do
  998. {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
  999. User.delete_user_activities(user)
  1000. # TODO: Test removal favorites, repeats, delete activities.
  1001. refute Activity.get_by_id(activity.id)
  1002. end
  1003. test "it deactivates a user, all follow relationships and all activities", %{user: user} do
  1004. follower = insert(:user)
  1005. {:ok, follower} = User.follow(follower, user)
  1006. locked_user = insert(:user, name: "locked", locked: true)
  1007. {:ok, _} = User.follow(user, locked_user, :follow_pending)
  1008. object = insert(:note, user: user)
  1009. activity = insert(:note_activity, user: user, note: object)
  1010. object_two = insert(:note, user: follower)
  1011. activity_two = insert(:note_activity, user: follower, note: object_two)
  1012. {:ok, like} = CommonAPI.favorite(user, activity_two.id)
  1013. {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
  1014. {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
  1015. {:ok, job} = User.delete(user)
  1016. {:ok, _user} = ObanHelpers.perform(job)
  1017. follower = User.get_cached_by_id(follower.id)
  1018. refute User.following?(follower, user)
  1019. assert %{deactivated: true} = User.get_by_id(user.id)
  1020. assert [] == User.get_follow_requests(locked_user)
  1021. user_activities =
  1022. user.ap_id
  1023. |> Activity.Queries.by_actor()
  1024. |> Repo.all()
  1025. |> Enum.map(fn act -> act.data["type"] end)
  1026. assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
  1027. refute Activity.get_by_id(activity.id)
  1028. refute Activity.get_by_id(like.id)
  1029. refute Activity.get_by_id(like_two.id)
  1030. refute Activity.get_by_id(repeat.id)
  1031. end
  1032. end
  1033. describe "delete/1 when confirmation is pending" do
  1034. setup do
  1035. user = insert(:user, confirmation_pending: true)
  1036. {:ok, user: user}
  1037. end
  1038. test "deletes user from database when activation required", %{user: user} do
  1039. clear_config([:instance, :account_activation_required], true)
  1040. {:ok, job} = User.delete(user)
  1041. {:ok, _} = ObanHelpers.perform(job)
  1042. refute User.get_cached_by_id(user.id)
  1043. refute User.get_by_id(user.id)
  1044. end
  1045. test "deactivates user when activation is not required", %{user: user} do
  1046. clear_config([:instance, :account_activation_required], false)
  1047. {:ok, job} = User.delete(user)
  1048. {:ok, _} = ObanHelpers.perform(job)
  1049. assert %{deactivated: true} = User.get_cached_by_id(user.id)
  1050. assert %{deactivated: true} = User.get_by_id(user.id)
  1051. end
  1052. end
  1053. test "delete/1 when approval is pending deletes the user" do
  1054. user = insert(:user, approval_pending: true)
  1055. {:ok, job} = User.delete(user)
  1056. {:ok, _} = ObanHelpers.perform(job)
  1057. refute User.get_cached_by_id(user.id)
  1058. refute User.get_by_id(user.id)
  1059. end
  1060. test "delete/1 purges a user when they wouldn't be fully deleted" do
  1061. user =
  1062. insert(:user, %{
  1063. bio: "eyy lmao",
  1064. name: "qqqqqqq",
  1065. password_hash: "pdfk2$1b3n159001",
  1066. keys: "RSA begin buplic key",
  1067. public_key: "--PRIVATE KEYE--",
  1068. avatar: %{"a" => "b"},
  1069. tags: ["qqqqq"],
  1070. banner: %{"a" => "b"},
  1071. background: %{"a" => "b"},
  1072. note_count: 9,
  1073. follower_count: 9,
  1074. following_count: 9001,
  1075. locked: true,
  1076. confirmation_pending: true,
  1077. password_reset_pending: true,
  1078. approval_pending: true,
  1079. registration_reason: "ahhhhh",
  1080. confirmation_token: "qqqq",
  1081. domain_blocks: ["lain.com"],
  1082. deactivated: true,
  1083. ap_enabled: true,
  1084. is_moderator: true,
  1085. is_admin: true,
  1086. mastofe_settings: %{"a" => "b"},
  1087. mascot: %{"a" => "b"},
  1088. emoji: %{"a" => "b"},
  1089. pleroma_settings_store: %{"q" => "x"},
  1090. fields: [%{"gg" => "qq"}],
  1091. raw_fields: [%{"gg" => "qq"}],
  1092. discoverable: true,
  1093. also_known_as: ["https://lol.olo/users/loll"]
  1094. })
  1095. {:ok, job} = User.delete(user)
  1096. {:ok, _} = ObanHelpers.perform(job)
  1097. user = User.get_by_id(user.id)
  1098. assert %User{
  1099. bio: "",
  1100. raw_bio: nil,
  1101. email: nil,
  1102. name: nil,
  1103. password_hash: nil,
  1104. keys: nil,
  1105. public_key: nil,
  1106. avatar: %{},
  1107. tags: [],
  1108. last_refreshed_at: nil,
  1109. last_digest_emailed_at: nil,
  1110. banner: %{},
  1111. background: %{},
  1112. note_count: 0,
  1113. follower_count: 0,
  1114. following_count: 0,
  1115. locked: false,
  1116. confirmation_pending: false,
  1117. password_reset_pending: false,
  1118. approval_pending: false,
  1119. registration_reason: nil,
  1120. confirmation_token: nil,
  1121. domain_blocks: [],
  1122. deactivated: true,
  1123. ap_enabled: false,
  1124. is_moderator: false,
  1125. is_admin: false,
  1126. mastofe_settings: nil,
  1127. mascot: nil,
  1128. emoji: %{},
  1129. pleroma_settings_store: %{},
  1130. fields: [],
  1131. raw_fields: [],
  1132. discoverable: false,
  1133. also_known_as: []
  1134. } = user
  1135. end
  1136. test "get_public_key_for_ap_id fetches a user that's not in the db" do
  1137. assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
  1138. end
  1139. describe "per-user rich-text filtering" do
  1140. test "html_filter_policy returns default policies, when rich-text is enabled" do
  1141. user = insert(:user)
  1142. assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
  1143. end
  1144. test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
  1145. user = insert(:user, no_rich_text: true)
  1146. assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
  1147. end
  1148. end
  1149. describe "caching" do
  1150. test "invalidate_cache works" do
  1151. user = insert(:user)
  1152. User.set_cache(user)
  1153. User.invalidate_cache(user)
  1154. {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1155. {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
  1156. end
  1157. test "User.delete() plugs any possible zombie objects" do
  1158. user = insert(:user)
  1159. {:ok, job} = User.delete(user)
  1160. {:ok, _} = ObanHelpers.perform(job)
  1161. {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1162. assert cached_user != user
  1163. {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
  1164. assert cached_user != user
  1165. end
  1166. end
  1167. describe "account_status/1" do
  1168. setup do: clear_config([:instance, :account_activation_required])
  1169. test "return confirmation_pending for unconfirm user" do
  1170. Pleroma.Config.put([:instance, :account_activation_required], true)
  1171. user = insert(:user, confirmation_pending: true)
  1172. assert User.account_status(user) == :confirmation_pending
  1173. end
  1174. test "return active for confirmed user" do
  1175. Pleroma.Config.put([:instance, :account_activation_required], true)
  1176. user = insert(:user, confirmation_pending: false)
  1177. assert User.account_status(user) == :active
  1178. end
  1179. test "return active for remote user" do
  1180. user = insert(:user, local: false)
  1181. assert User.account_status(user) == :active
  1182. end
  1183. test "returns :password_reset_pending for user with reset password" do
  1184. user = insert(:user, password_reset_pending: true)
  1185. assert User.account_status(user) == :password_reset_pending
  1186. end
  1187. test "returns :deactivated for deactivated user" do
  1188. user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
  1189. assert User.account_status(user) == :deactivated
  1190. end
  1191. test "returns :approval_pending for unapproved user" do
  1192. user = insert(:user, local: true, approval_pending: true)
  1193. assert User.account_status(user) == :approval_pending
  1194. user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
  1195. assert User.account_status(user) == :approval_pending
  1196. end
  1197. end
  1198. describe "superuser?/1" do
  1199. test "returns false for unprivileged users" do
  1200. user = insert(:user, local: true)
  1201. refute User.superuser?(user)
  1202. end
  1203. test "returns false for remote users" do
  1204. user = insert(:user, local: false)
  1205. remote_admin_user = insert(:user, local: false, is_admin: true)
  1206. refute User.superuser?(user)
  1207. refute User.superuser?(remote_admin_user)
  1208. end
  1209. test "returns true for local moderators" do
  1210. user = insert(:user, local: true, is_moderator: true)
  1211. assert User.superuser?(user)
  1212. end
  1213. test "returns true for local admins" do
  1214. user = insert(:user, local: true, is_admin: true)
  1215. assert User.superuser?(user)
  1216. end
  1217. end
  1218. describe "invisible?/1" do
  1219. test "returns true for an invisible user" do
  1220. user = insert(:user, local: true, invisible: true)
  1221. assert User.invisible?(user)
  1222. end
  1223. test "returns false for a non-invisible user" do
  1224. user = insert(:user, local: true)
  1225. refute User.invisible?(user)
  1226. end
  1227. end
  1228. describe "visible_for/2" do
  1229. test "returns true when the account is itself" do
  1230. user = insert(:user, local: true)
  1231. assert User.visible_for(user, user) == :visible
  1232. end
  1233. test "returns false when the account is unconfirmed and confirmation is required" do
  1234. Pleroma.Config.put([:instance, :account_activation_required], true)
  1235. user = insert(:user, local: true, confirmation_pending: true)
  1236. other_user = insert(:user, local: true)
  1237. refute User.visible_for(user, other_user) == :visible
  1238. end
  1239. test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
  1240. Pleroma.Config.put([:instance, :account_activation_required], true)
  1241. user = insert(:user, local: false, confirmation_pending: true)
  1242. other_user = insert(:user, local: true)
  1243. assert User.visible_for(user, other_user) == :visible
  1244. end
  1245. test "returns true when the account is unconfirmed and confirmation is not required" do
  1246. user = insert(:user, local: true, confirmation_pending: true)
  1247. other_user = insert(:user, local: true)
  1248. assert User.visible_for(user, other_user) == :visible
  1249. end
  1250. test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
  1251. Pleroma.Config.put([:instance, :account_activation_required], true)
  1252. user = insert(:user, local: true, confirmation_pending: true)
  1253. other_user = insert(:user, local: true, is_admin: true)
  1254. assert User.visible_for(user, other_user) == :visible
  1255. end
  1256. end
  1257. describe "parse_bio/2" do
  1258. test "preserves hosts in user links text" do
  1259. remote_user = insert(:user, local: false, nickname: "nick@domain.com")
  1260. user = insert(:user)
  1261. bio = "A.k.a. @nick@domain.com"
  1262. expected_text =
  1263. ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
  1264. remote_user.ap_id
  1265. }" rel="ugc">@<span>nick@domain.com</span></a></span>)
  1266. assert expected_text == User.parse_bio(bio, user)
  1267. end
  1268. test "Adds rel=me on linkbacked urls" do
  1269. user = insert(:user, ap_id: "https://social.example.org/users/lain")
  1270. bio = "http://example.com/rel_me/null"
  1271. expected_text = "<a href=\"#{bio}\">#{bio}</a>"
  1272. assert expected_text == User.parse_bio(bio, user)
  1273. bio = "http://example.com/rel_me/link"
  1274. expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
  1275. assert expected_text == User.parse_bio(bio, user)
  1276. bio = "http://example.com/rel_me/anchor"
  1277. expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
  1278. assert expected_text == User.parse_bio(bio, user)
  1279. end
  1280. end
  1281. test "follower count is updated when a follower is blocked" do
  1282. user = insert(:user)
  1283. follower = insert(:user)
  1284. follower2 = insert(:user)
  1285. follower3 = insert(:user)
  1286. {:ok, follower} = User.follow(follower, user)
  1287. {:ok, _follower2} = User.follow(follower2, user)
  1288. {:ok, _follower3} = User.follow(follower3, user)
  1289. {:ok, _user_relationship} = User.block(user, follower)
  1290. user = refresh_record(user)
  1291. assert user.follower_count == 2
  1292. end
  1293. describe "list_inactive_users_query/1" do
  1294. defp days_ago(days) do
  1295. NaiveDateTime.add(
  1296. NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
  1297. -days * 60 * 60 * 24,
  1298. :second
  1299. )
  1300. end
  1301. test "Users are inactive by default" do
  1302. total = 10
  1303. users =
  1304. Enum.map(1..total, fn _ ->
  1305. insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
  1306. end)
  1307. inactive_users_ids =
  1308. Pleroma.User.list_inactive_users_query()
  1309. |> Pleroma.Repo.all()
  1310. |> Enum.map(& &1.id)
  1311. Enum.each(users, fn user ->
  1312. assert user.id in inactive_users_ids
  1313. end)
  1314. end
  1315. test "Only includes users who has no recent activity" do
  1316. total = 10
  1317. users =
  1318. Enum.map(1..total, fn _ ->
  1319. insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
  1320. end)
  1321. {inactive, active} = Enum.split(users, trunc(total / 2))
  1322. Enum.map(active, fn user ->
  1323. to = Enum.random(users -- [user])
  1324. {:ok, _} =
  1325. CommonAPI.post(user, %{
  1326. status: "hey @#{to.nickname}"
  1327. })
  1328. end)
  1329. inactive_users_ids =
  1330. Pleroma.User.list_inactive_users_query()
  1331. |> Pleroma.Repo.all()
  1332. |> Enum.map(& &1.id)
  1333. Enum.each(active, fn user ->
  1334. refute user.id in inactive_users_ids
  1335. end)
  1336. Enum.each(inactive, fn user ->
  1337. assert user.id in inactive_users_ids
  1338. end)
  1339. end
  1340. test "Only includes users with no read notifications" do
  1341. total = 10
  1342. users =
  1343. Enum.map(1..total, fn _ ->
  1344. insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
  1345. end)
  1346. [sender | recipients] = users
  1347. {inactive, active} = Enum.split(recipients, trunc(total / 2))
  1348. Enum.each(recipients, fn to ->
  1349. {:ok, _} =
  1350. CommonAPI.post(sender, %{
  1351. status: "hey @#{to.nickname}"
  1352. })
  1353. {:ok, _} =
  1354. CommonAPI.post(sender, %{
  1355. status: "hey again @#{to.nickname}"
  1356. })
  1357. end)
  1358. Enum.each(active, fn user ->
  1359. [n1, _n2] = Pleroma.Notification.for_user(user)
  1360. {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
  1361. end)
  1362. inactive_users_ids =
  1363. Pleroma.User.list_inactive_users_query()
  1364. |> Pleroma.Repo.all()
  1365. |> Enum.map(& &1.id)
  1366. Enum.each(active, fn user ->
  1367. refute user.id in inactive_users_ids
  1368. end)
  1369. Enum.each(inactive, fn user ->
  1370. assert user.id in inactive_users_ids
  1371. end)
  1372. end
  1373. end
  1374. describe "toggle_confirmation/1" do
  1375. test "if user is confirmed" do
  1376. user = insert(:user, confirmation_pending: false)
  1377. {:ok, user} = User.toggle_confirmation(user)
  1378. assert user.confirmation_pending
  1379. assert user.confirmation_token
  1380. end
  1381. test "if user is unconfirmed" do
  1382. user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
  1383. {:ok, user} = User.toggle_confirmation(user)
  1384. refute user.confirmation_pending
  1385. refute user.confirmation_token
  1386. end
  1387. end
  1388. describe "ensure_keys_present" do
  1389. test "it creates keys for a user and stores them in info" do
  1390. user = insert(:user)
  1391. refute is_binary(user.keys)
  1392. {:ok, user} = User.ensure_keys_present(user)
  1393. assert is_binary(user.keys)
  1394. end
  1395. test "it doesn't create keys if there already are some" do
  1396. user = insert(:user, keys: "xxx")
  1397. {:ok, user} = User.ensure_keys_present(user)
  1398. assert user.keys == "xxx"
  1399. end
  1400. end
  1401. describe "get_ap_ids_by_nicknames" do
  1402. test "it returns a list of AP ids for a given set of nicknames" do
  1403. user = insert(:user)
  1404. user_two = insert(:user)
  1405. ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
  1406. assert length(ap_ids) == 2
  1407. assert user.ap_id in ap_ids
  1408. assert user_two.ap_id in ap_ids
  1409. end
  1410. end
  1411. describe "sync followers count" do
  1412. setup do
  1413. user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
  1414. user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
  1415. insert(:user, local: true)
  1416. insert(:user, local: false, deactivated: true)
  1417. {:ok, user1: user1, user2: user2}
  1418. end
  1419. test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
  1420. [fdb_user1] = User.external_users(limit: 1)
  1421. assert fdb_user1.ap_id
  1422. assert fdb_user1.ap_id == user1.ap_id
  1423. assert fdb_user1.id == user1.id
  1424. [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
  1425. assert fdb_user2.ap_id
  1426. assert fdb_user2.ap_id == user2.ap_id
  1427. assert fdb_user2.id == user2.id
  1428. assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
  1429. end
  1430. end
  1431. describe "is_internal_user?/1" do
  1432. test "non-internal user returns false" do
  1433. user = insert(:user)
  1434. refute User.is_internal_user?(user)
  1435. end
  1436. test "user with no nickname returns true" do
  1437. user = insert(:user, %{nickname: nil})
  1438. assert User.is_internal_user?(user)
  1439. end
  1440. test "user with internal-prefixed nickname returns true" do
  1441. user = insert(:user, %{nickname: "internal.test"})
  1442. assert User.is_internal_user?(user)
  1443. end
  1444. end
  1445. describe "update_and_set_cache/1" do
  1446. test "returns error when user is stale instead Ecto.StaleEntryError" do
  1447. user = insert(:user)
  1448. changeset = Ecto.Changeset.change(user, bio: "test")
  1449. Repo.delete(user)
  1450. assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
  1451. User.update_and_set_cache(changeset)
  1452. end
  1453. test "performs update cache if user updated" do
  1454. user = insert(:user)
  1455. assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1456. changeset = Ecto.Changeset.change(user, bio: "test-bio")
  1457. assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
  1458. assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1459. assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
  1460. end
  1461. end
  1462. describe "following/followers synchronization" do
  1463. setup do: clear_config([:instance, :external_user_synchronization])
  1464. test "updates the counters normally on following/getting a follow when disabled" do
  1465. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1466. user = insert(:user)
  1467. other_user =
  1468. insert(:user,
  1469. local: false,
  1470. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1471. following_address: "http://localhost:4001/users/masto_closed/following",
  1472. ap_enabled: true
  1473. )
  1474. assert other_user.following_count == 0
  1475. assert other_user.follower_count == 0
  1476. {:ok, user} = Pleroma.User.follow(user, other_user)
  1477. other_user = Pleroma.User.get_by_id(other_user.id)
  1478. assert user.following_count == 1
  1479. assert other_user.follower_count == 1
  1480. end
  1481. test "syncronizes the counters with the remote instance for the followed when enabled" do
  1482. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1483. user = insert(:user)
  1484. other_user =
  1485. insert(:user,
  1486. local: false,
  1487. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1488. following_address: "http://localhost:4001/users/masto_closed/following",
  1489. ap_enabled: true
  1490. )
  1491. assert other_user.following_count == 0
  1492. assert other_user.follower_count == 0
  1493. Pleroma.Config.put([:instance, :external_user_synchronization], true)
  1494. {:ok, _user} = User.follow(user, other_user)
  1495. other_user = User.get_by_id(other_user.id)
  1496. assert other_user.follower_count == 437
  1497. end
  1498. test "syncronizes the counters with the remote instance for the follower when enabled" do
  1499. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1500. user = insert(:user)
  1501. other_user =
  1502. insert(:user,
  1503. local: false,
  1504. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1505. following_address: "http://localhost:4001/users/masto_closed/following",
  1506. ap_enabled: true
  1507. )
  1508. assert other_user.following_count == 0
  1509. assert other_user.follower_count == 0
  1510. Pleroma.Config.put([:instance, :external_user_synchronization], true)
  1511. {:ok, other_user} = User.follow(other_user, user)
  1512. assert other_user.following_count == 152
  1513. end
  1514. end
  1515. describe "change_email/2" do
  1516. setup do
  1517. [user: insert(:user)]
  1518. end
  1519. test "blank email returns error", %{user: user} do
  1520. assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
  1521. assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
  1522. end
  1523. test "non unique email returns error", %{user: user} do
  1524. %{email: email} = insert(:user)
  1525. assert {:error, %{errors: [email: {"has already been taken", _}]}} =
  1526. User.change_email(user, email)
  1527. end
  1528. test "invalid email returns error", %{user: user} do
  1529. assert {:error, %{errors: [email: {"has invalid format", _}]}} =
  1530. User.change_email(user, "cofe")
  1531. end
  1532. test "changes email", %{user: user} do
  1533. assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
  1534. end
  1535. end
  1536. describe "get_cached_by_nickname_or_id" do
  1537. setup do
  1538. local_user = insert(:user)
  1539. remote_user = insert(:user, nickname: "nickname@example.com", local: false)
  1540. [local_user: local_user, remote_user: remote_user]
  1541. end
  1542. setup do: clear_config([:instance, :limit_to_local_content])
  1543. test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
  1544. remote_user: remote_user
  1545. } do
  1546. Pleroma.Config.put([:instance, :limit_to_local_content], false)
  1547. assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
  1548. Pleroma.Config.put([:instance, :limit_to_local_content], true)
  1549. assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
  1550. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  1551. assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
  1552. end
  1553. test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
  1554. %{remote_user: remote_user} do
  1555. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  1556. assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
  1557. end
  1558. test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
  1559. %{remote_user: remote_user, local_user: local_user} do
  1560. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  1561. assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
  1562. end
  1563. test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
  1564. %{remote_user: remote_user} do
  1565. Pleroma.Config.put([:instance, :limit_to_local_content], true)
  1566. assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
  1567. end
  1568. test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
  1569. %{local_user: local_user} do
  1570. Pleroma.Config.put([:instance, :limit_to_local_content], false)
  1571. assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
  1572. Pleroma.Config.put([:instance, :limit_to_local_content], true)
  1573. assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
  1574. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  1575. assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
  1576. end
  1577. end
  1578. describe "update_email_notifications/2" do
  1579. setup do
  1580. user = insert(:user, email_notifications: %{"digest" => true})
  1581. {:ok, user: user}
  1582. end
  1583. test "Notifications are updated", %{user: user} do
  1584. true = user.email_notifications["digest"]
  1585. assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
  1586. assert result.email_notifications["digest"] == false
  1587. end
  1588. end
  1589. test "avatar fallback" do
  1590. user = insert(:user)
  1591. assert User.avatar_url(user) =~ "/images/avi.png"
  1592. clear_config([:assets, :default_user_avatar], "avatar.png")
  1593. user = User.get_cached_by_nickname_or_id(user.nickname)
  1594. assert User.avatar_url(user) =~ "avatar.png"
  1595. assert User.avatar_url(user, no_default: true) == nil
  1596. end
  1597. end