logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma

user_test.exs (67394B)


  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. Pleroma.Emails.UserEmail.account_confirmation_email(registered_user)
  389. # temporary hackney fix until hackney max_connections bug is fixed
  390. # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
  391. |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
  392. |> assert_email_sent()
  393. end
  394. test "it requires an email, name, nickname and password, bio is optional when account_activation_required is enabled" do
  395. Pleroma.Config.put([:instance, :account_activation_required], true)
  396. @full_user_data
  397. |> Map.keys()
  398. |> Enum.each(fn key ->
  399. params = Map.delete(@full_user_data, key)
  400. changeset = User.register_changeset(%User{}, params)
  401. assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
  402. end)
  403. end
  404. test "it requires an name, nickname and password, bio and email are optional when account_activation_required is disabled" do
  405. Pleroma.Config.put([:instance, :account_activation_required], false)
  406. @full_user_data
  407. |> Map.keys()
  408. |> Enum.each(fn key ->
  409. params = Map.delete(@full_user_data, key)
  410. changeset = User.register_changeset(%User{}, params)
  411. assert if key in [:bio, :email], do: changeset.valid?, else: not changeset.valid?
  412. end)
  413. end
  414. test "it restricts certain nicknames" do
  415. [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
  416. assert is_bitstring(restricted_name)
  417. params =
  418. @full_user_data
  419. |> Map.put(:nickname, restricted_name)
  420. changeset = User.register_changeset(%User{}, params)
  421. refute changeset.valid?
  422. end
  423. test "it blocks blacklisted email domains" do
  424. clear_config([User, :email_blacklist], ["trolling.world"])
  425. # Block with match
  426. params = Map.put(@full_user_data, :email, "troll@trolling.world")
  427. changeset = User.register_changeset(%User{}, params)
  428. refute changeset.valid?
  429. # Block with subdomain match
  430. params = Map.put(@full_user_data, :email, "troll@gnomes.trolling.world")
  431. changeset = User.register_changeset(%User{}, params)
  432. refute changeset.valid?
  433. # Pass with different domains that are similar
  434. params = Map.put(@full_user_data, :email, "troll@gnomestrolling.world")
  435. changeset = User.register_changeset(%User{}, params)
  436. assert changeset.valid?
  437. params = Map.put(@full_user_data, :email, "troll@trolling.world.us")
  438. changeset = User.register_changeset(%User{}, params)
  439. assert changeset.valid?
  440. end
  441. test "it sets the password_hash and ap_id" do
  442. changeset = User.register_changeset(%User{}, @full_user_data)
  443. assert changeset.valid?
  444. assert is_binary(changeset.changes[:password_hash])
  445. assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
  446. assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
  447. end
  448. test "it sets the 'accepts_chat_messages' set to true" do
  449. changeset = User.register_changeset(%User{}, @full_user_data)
  450. assert changeset.valid?
  451. {:ok, user} = Repo.insert(changeset)
  452. assert user.accepts_chat_messages
  453. end
  454. test "it creates a confirmed user" do
  455. changeset = User.register_changeset(%User{}, @full_user_data)
  456. assert changeset.valid?
  457. {:ok, user} = Repo.insert(changeset)
  458. refute user.confirmation_pending
  459. end
  460. end
  461. describe "user registration, with :account_activation_required" do
  462. @full_user_data %{
  463. bio: "A guy",
  464. name: "my name",
  465. nickname: "nick",
  466. password: "test",
  467. password_confirmation: "test",
  468. email: "email@example.com"
  469. }
  470. setup do: clear_config([:instance, :account_activation_required], true)
  471. test "it creates unconfirmed user" do
  472. changeset = User.register_changeset(%User{}, @full_user_data)
  473. assert changeset.valid?
  474. {:ok, user} = Repo.insert(changeset)
  475. assert user.confirmation_pending
  476. assert user.confirmation_token
  477. end
  478. test "it creates confirmed user if :confirmed option is given" do
  479. changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
  480. assert changeset.valid?
  481. {:ok, user} = Repo.insert(changeset)
  482. refute user.confirmation_pending
  483. refute user.confirmation_token
  484. end
  485. end
  486. describe "user registration, with :account_approval_required" do
  487. @full_user_data %{
  488. bio: "A guy",
  489. name: "my name",
  490. nickname: "nick",
  491. password: "test",
  492. password_confirmation: "test",
  493. email: "email@example.com",
  494. registration_reason: "I'm a cool guy :)"
  495. }
  496. setup do: clear_config([:instance, :account_approval_required], true)
  497. test "it creates unapproved user" do
  498. changeset = User.register_changeset(%User{}, @full_user_data)
  499. assert changeset.valid?
  500. {:ok, user} = Repo.insert(changeset)
  501. assert user.approval_pending
  502. assert user.registration_reason == "I'm a cool guy :)"
  503. end
  504. test "it restricts length of registration reason" do
  505. reason_limit = Pleroma.Config.get([:instance, :registration_reason_length])
  506. assert is_integer(reason_limit)
  507. params =
  508. @full_user_data
  509. |> Map.put(
  510. :registration_reason,
  511. "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."
  512. )
  513. changeset = User.register_changeset(%User{}, params)
  514. refute changeset.valid?
  515. end
  516. end
  517. describe "get_or_fetch/1" do
  518. test "gets an existing user by nickname" do
  519. user = insert(:user)
  520. {:ok, fetched_user} = User.get_or_fetch(user.nickname)
  521. assert user == fetched_user
  522. end
  523. test "gets an existing user by ap_id" do
  524. ap_id = "http://mastodon.example.org/users/admin"
  525. user =
  526. insert(
  527. :user,
  528. local: false,
  529. nickname: "admin@mastodon.example.org",
  530. ap_id: ap_id
  531. )
  532. {:ok, fetched_user} = User.get_or_fetch(ap_id)
  533. freshed_user = refresh_record(user)
  534. assert freshed_user == fetched_user
  535. end
  536. end
  537. describe "fetching a user from nickname or trying to build one" do
  538. test "gets an existing user" do
  539. user = insert(:user)
  540. {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
  541. assert user == fetched_user
  542. end
  543. test "gets an existing user, case insensitive" do
  544. user = insert(:user, nickname: "nick")
  545. {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
  546. assert user == fetched_user
  547. end
  548. test "gets an existing user by fully qualified nickname" do
  549. user = insert(:user)
  550. {:ok, fetched_user} =
  551. User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
  552. assert user == fetched_user
  553. end
  554. test "gets an existing user by fully qualified nickname, case insensitive" do
  555. user = insert(:user, nickname: "nick")
  556. casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
  557. {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
  558. assert user == fetched_user
  559. end
  560. @tag capture_log: true
  561. test "returns nil if no user could be fetched" do
  562. {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
  563. assert fetched_user == "not found nonexistant@social.heldscal.la"
  564. end
  565. test "returns nil for nonexistant local user" do
  566. {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
  567. assert fetched_user == "not found nonexistant"
  568. end
  569. test "updates an existing user, if stale" do
  570. a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
  571. orig_user =
  572. insert(
  573. :user,
  574. local: false,
  575. nickname: "admin@mastodon.example.org",
  576. ap_id: "http://mastodon.example.org/users/admin",
  577. last_refreshed_at: a_week_ago
  578. )
  579. assert orig_user.last_refreshed_at == a_week_ago
  580. {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
  581. assert user.inbox
  582. refute user.last_refreshed_at == orig_user.last_refreshed_at
  583. end
  584. test "if nicknames clash, the old user gets a prefix with the old id to the nickname" do
  585. a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
  586. orig_user =
  587. insert(
  588. :user,
  589. local: false,
  590. nickname: "admin@mastodon.example.org",
  591. ap_id: "http://mastodon.example.org/users/harinezumigari",
  592. last_refreshed_at: a_week_ago
  593. )
  594. assert orig_user.last_refreshed_at == a_week_ago
  595. {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
  596. assert user.inbox
  597. refute user.id == orig_user.id
  598. orig_user = User.get_by_id(orig_user.id)
  599. assert orig_user.nickname == "#{orig_user.id}.admin@mastodon.example.org"
  600. end
  601. @tag capture_log: true
  602. test "it returns the old user if stale, but unfetchable" do
  603. a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
  604. orig_user =
  605. insert(
  606. :user,
  607. local: false,
  608. nickname: "admin@mastodon.example.org",
  609. ap_id: "http://mastodon.example.org/users/raymoo",
  610. last_refreshed_at: a_week_ago
  611. )
  612. assert orig_user.last_refreshed_at == a_week_ago
  613. {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/raymoo")
  614. assert user.last_refreshed_at == orig_user.last_refreshed_at
  615. end
  616. end
  617. test "returns an ap_id for a user" do
  618. user = insert(:user)
  619. assert User.ap_id(user) ==
  620. Pleroma.Web.Router.Helpers.user_feed_url(
  621. Pleroma.Web.Endpoint,
  622. :feed_redirect,
  623. user.nickname
  624. )
  625. end
  626. test "returns an ap_followers link for a user" do
  627. user = insert(:user)
  628. assert User.ap_followers(user) ==
  629. Pleroma.Web.Router.Helpers.user_feed_url(
  630. Pleroma.Web.Endpoint,
  631. :feed_redirect,
  632. user.nickname
  633. ) <> "/followers"
  634. end
  635. describe "remote user changeset" do
  636. @valid_remote %{
  637. bio: "hello",
  638. name: "Someone",
  639. nickname: "a@b.de",
  640. ap_id: "http...",
  641. avatar: %{some: "avatar"}
  642. }
  643. setup do: clear_config([:instance, :user_bio_length])
  644. setup do: clear_config([:instance, :user_name_length])
  645. test "it confirms validity" do
  646. cs = User.remote_user_changeset(@valid_remote)
  647. assert cs.valid?
  648. end
  649. test "it sets the follower_adress" do
  650. cs = User.remote_user_changeset(@valid_remote)
  651. # remote users get a fake local follower address
  652. assert cs.changes.follower_address ==
  653. User.ap_followers(%User{nickname: @valid_remote[:nickname]})
  654. end
  655. test "it enforces the fqn format for nicknames" do
  656. cs = User.remote_user_changeset(%{@valid_remote | nickname: "bla"})
  657. assert Ecto.Changeset.get_field(cs, :local) == false
  658. assert cs.changes.avatar
  659. refute cs.valid?
  660. end
  661. test "it has required fields" do
  662. [:ap_id]
  663. |> Enum.each(fn field ->
  664. cs = User.remote_user_changeset(Map.delete(@valid_remote, field))
  665. refute cs.valid?
  666. end)
  667. end
  668. end
  669. describe "followers and friends" do
  670. test "gets all followers for a given user" do
  671. user = insert(:user)
  672. follower_one = insert(:user)
  673. follower_two = insert(:user)
  674. not_follower = insert(:user)
  675. {:ok, follower_one} = User.follow(follower_one, user)
  676. {:ok, follower_two} = User.follow(follower_two, user)
  677. res = User.get_followers(user)
  678. assert Enum.member?(res, follower_one)
  679. assert Enum.member?(res, follower_two)
  680. refute Enum.member?(res, not_follower)
  681. end
  682. test "gets all friends (followed users) for a given user" do
  683. user = insert(:user)
  684. followed_one = insert(:user)
  685. followed_two = insert(:user)
  686. not_followed = insert(:user)
  687. {:ok, user} = User.follow(user, followed_one)
  688. {:ok, user} = User.follow(user, followed_two)
  689. res = User.get_friends(user)
  690. followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
  691. followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
  692. assert Enum.member?(res, followed_one)
  693. assert Enum.member?(res, followed_two)
  694. refute Enum.member?(res, not_followed)
  695. end
  696. end
  697. describe "updating note and follower count" do
  698. test "it sets the note_count property" do
  699. note = insert(:note)
  700. user = User.get_cached_by_ap_id(note.data["actor"])
  701. assert user.note_count == 0
  702. {:ok, user} = User.update_note_count(user)
  703. assert user.note_count == 1
  704. end
  705. test "it increases the note_count property" do
  706. note = insert(:note)
  707. user = User.get_cached_by_ap_id(note.data["actor"])
  708. assert user.note_count == 0
  709. {:ok, user} = User.increase_note_count(user)
  710. assert user.note_count == 1
  711. {:ok, user} = User.increase_note_count(user)
  712. assert user.note_count == 2
  713. end
  714. test "it decreases the note_count property" do
  715. note = insert(:note)
  716. user = User.get_cached_by_ap_id(note.data["actor"])
  717. assert user.note_count == 0
  718. {:ok, user} = User.increase_note_count(user)
  719. assert user.note_count == 1
  720. {:ok, user} = User.decrease_note_count(user)
  721. assert user.note_count == 0
  722. {:ok, user} = User.decrease_note_count(user)
  723. assert user.note_count == 0
  724. end
  725. test "it sets the follower_count property" do
  726. user = insert(:user)
  727. follower = insert(:user)
  728. User.follow(follower, user)
  729. assert user.follower_count == 0
  730. {:ok, user} = User.update_follower_count(user)
  731. assert user.follower_count == 1
  732. end
  733. end
  734. describe "mutes" do
  735. test "it mutes people" do
  736. user = insert(:user)
  737. muted_user = insert(:user)
  738. refute User.mutes?(user, muted_user)
  739. refute User.muted_notifications?(user, muted_user)
  740. {:ok, _user_relationships} = User.mute(user, muted_user)
  741. assert User.mutes?(user, muted_user)
  742. assert User.muted_notifications?(user, muted_user)
  743. end
  744. test "it unmutes users" do
  745. user = insert(:user)
  746. muted_user = insert(:user)
  747. {:ok, _user_relationships} = User.mute(user, muted_user)
  748. {:ok, _user_mute} = User.unmute(user, muted_user)
  749. refute User.mutes?(user, muted_user)
  750. refute User.muted_notifications?(user, muted_user)
  751. end
  752. test "it mutes user without notifications" do
  753. user = insert(:user)
  754. muted_user = insert(:user)
  755. refute User.mutes?(user, muted_user)
  756. refute User.muted_notifications?(user, muted_user)
  757. {:ok, _user_relationships} = User.mute(user, muted_user, false)
  758. assert User.mutes?(user, muted_user)
  759. refute User.muted_notifications?(user, muted_user)
  760. end
  761. end
  762. describe "blocks" do
  763. test "it blocks people" do
  764. user = insert(:user)
  765. blocked_user = insert(:user)
  766. refute User.blocks?(user, blocked_user)
  767. {:ok, _user_relationship} = User.block(user, blocked_user)
  768. assert User.blocks?(user, blocked_user)
  769. end
  770. test "it unblocks users" do
  771. user = insert(:user)
  772. blocked_user = insert(:user)
  773. {:ok, _user_relationship} = User.block(user, blocked_user)
  774. {:ok, _user_block} = User.unblock(user, blocked_user)
  775. refute User.blocks?(user, blocked_user)
  776. end
  777. test "blocks tear down cyclical follow relationships" do
  778. blocker = insert(:user)
  779. blocked = insert(:user)
  780. {:ok, blocker} = User.follow(blocker, blocked)
  781. {:ok, blocked} = User.follow(blocked, blocker)
  782. assert User.following?(blocker, blocked)
  783. assert User.following?(blocked, blocker)
  784. {:ok, _user_relationship} = User.block(blocker, blocked)
  785. blocked = User.get_cached_by_id(blocked.id)
  786. assert User.blocks?(blocker, blocked)
  787. refute User.following?(blocker, blocked)
  788. refute User.following?(blocked, blocker)
  789. end
  790. test "blocks tear down blocker->blocked follow relationships" do
  791. blocker = insert(:user)
  792. blocked = insert(:user)
  793. {:ok, blocker} = User.follow(blocker, blocked)
  794. assert User.following?(blocker, blocked)
  795. refute User.following?(blocked, blocker)
  796. {:ok, _user_relationship} = User.block(blocker, blocked)
  797. blocked = User.get_cached_by_id(blocked.id)
  798. assert User.blocks?(blocker, blocked)
  799. refute User.following?(blocker, blocked)
  800. refute User.following?(blocked, blocker)
  801. end
  802. test "blocks tear down blocked->blocker follow relationships" do
  803. blocker = insert(:user)
  804. blocked = insert(:user)
  805. {:ok, blocked} = User.follow(blocked, blocker)
  806. refute User.following?(blocker, blocked)
  807. assert User.following?(blocked, blocker)
  808. {:ok, _user_relationship} = User.block(blocker, blocked)
  809. blocked = User.get_cached_by_id(blocked.id)
  810. assert User.blocks?(blocker, blocked)
  811. refute User.following?(blocker, blocked)
  812. refute User.following?(blocked, blocker)
  813. end
  814. test "blocks tear down blocked->blocker subscription relationships" do
  815. blocker = insert(:user)
  816. blocked = insert(:user)
  817. {:ok, _subscription} = User.subscribe(blocked, blocker)
  818. assert User.subscribed_to?(blocked, blocker)
  819. refute User.subscribed_to?(blocker, blocked)
  820. {:ok, _user_relationship} = User.block(blocker, blocked)
  821. assert User.blocks?(blocker, blocked)
  822. refute User.subscribed_to?(blocker, blocked)
  823. refute User.subscribed_to?(blocked, blocker)
  824. end
  825. end
  826. describe "domain blocking" do
  827. test "blocks domains" do
  828. user = insert(:user)
  829. collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  830. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  831. assert User.blocks?(user, collateral_user)
  832. end
  833. test "does not block domain with same end" do
  834. user = insert(:user)
  835. collateral_user =
  836. insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
  837. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  838. refute User.blocks?(user, collateral_user)
  839. end
  840. test "does not block domain with same end if wildcard added" do
  841. user = insert(:user)
  842. collateral_user =
  843. insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
  844. {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
  845. refute User.blocks?(user, collateral_user)
  846. end
  847. test "blocks domain with wildcard for subdomain" do
  848. user = insert(:user)
  849. user_from_subdomain =
  850. insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
  851. user_with_two_subdomains =
  852. insert(:user, %{
  853. ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
  854. })
  855. user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  856. {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
  857. assert User.blocks?(user, user_from_subdomain)
  858. assert User.blocks?(user, user_with_two_subdomains)
  859. assert User.blocks?(user, user_domain)
  860. end
  861. test "unblocks domains" do
  862. user = insert(:user)
  863. collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  864. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  865. {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
  866. refute User.blocks?(user, collateral_user)
  867. end
  868. test "follows take precedence over domain blocks" do
  869. user = insert(:user)
  870. good_eggo = insert(:user, %{ap_id: "https://meanies.social/user/cuteposter"})
  871. {:ok, user} = User.block_domain(user, "meanies.social")
  872. {:ok, user} = User.follow(user, good_eggo)
  873. refute User.blocks?(user, good_eggo)
  874. end
  875. end
  876. describe "get_recipients_from_activity" do
  877. test "works for announces" do
  878. actor = insert(:user)
  879. user = insert(:user, local: true)
  880. {:ok, activity} = CommonAPI.post(actor, %{status: "hello"})
  881. {:ok, announce} = CommonAPI.repeat(activity.id, user)
  882. recipients = User.get_recipients_from_activity(announce)
  883. assert user in recipients
  884. end
  885. test "get recipients" do
  886. actor = insert(:user)
  887. user = insert(:user, local: true)
  888. user_two = insert(:user, local: false)
  889. addressed = insert(:user, local: true)
  890. addressed_remote = insert(:user, local: false)
  891. {:ok, activity} =
  892. CommonAPI.post(actor, %{
  893. status: "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
  894. })
  895. assert Enum.map([actor, addressed], & &1.ap_id) --
  896. Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
  897. {:ok, user} = User.follow(user, actor)
  898. {:ok, _user_two} = User.follow(user_two, actor)
  899. recipients = User.get_recipients_from_activity(activity)
  900. assert length(recipients) == 3
  901. assert user in recipients
  902. assert addressed in recipients
  903. end
  904. test "has following" do
  905. actor = insert(:user)
  906. user = insert(:user)
  907. user_two = insert(:user)
  908. addressed = insert(:user, local: true)
  909. {:ok, activity} =
  910. CommonAPI.post(actor, %{
  911. status: "hey @#{addressed.nickname}"
  912. })
  913. assert Enum.map([actor, addressed], & &1.ap_id) --
  914. Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
  915. {:ok, _actor} = User.follow(actor, user)
  916. {:ok, _actor} = User.follow(actor, user_two)
  917. recipients = User.get_recipients_from_activity(activity)
  918. assert length(recipients) == 2
  919. assert addressed in recipients
  920. end
  921. end
  922. describe ".deactivate" do
  923. test "can de-activate then re-activate a user" do
  924. user = insert(:user)
  925. assert false == user.deactivated
  926. {:ok, user} = User.deactivate(user)
  927. assert true == user.deactivated
  928. {:ok, user} = User.deactivate(user, false)
  929. assert false == user.deactivated
  930. end
  931. test "hide a user from followers" do
  932. user = insert(:user)
  933. user2 = insert(:user)
  934. {:ok, user} = User.follow(user, user2)
  935. {:ok, _user} = User.deactivate(user)
  936. user2 = User.get_cached_by_id(user2.id)
  937. assert user2.follower_count == 0
  938. assert [] = User.get_followers(user2)
  939. end
  940. test "hide a user from friends" do
  941. user = insert(:user)
  942. user2 = insert(:user)
  943. {:ok, user2} = User.follow(user2, user)
  944. assert user2.following_count == 1
  945. assert User.following_count(user2) == 1
  946. {:ok, _user} = User.deactivate(user)
  947. user2 = User.get_cached_by_id(user2.id)
  948. assert refresh_record(user2).following_count == 0
  949. assert user2.following_count == 0
  950. assert User.following_count(user2) == 0
  951. assert [] = User.get_friends(user2)
  952. end
  953. test "hide a user's statuses from timelines and notifications" do
  954. user = insert(:user)
  955. user2 = insert(:user)
  956. {:ok, user2} = User.follow(user2, user)
  957. {:ok, activity} = CommonAPI.post(user, %{status: "hey @#{user2.nickname}"})
  958. activity = Repo.preload(activity, :bookmark)
  959. [notification] = Pleroma.Notification.for_user(user2)
  960. assert notification.activity.id == activity.id
  961. assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
  962. assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
  963. ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
  964. user: user2
  965. })
  966. {:ok, _user} = User.deactivate(user)
  967. assert [] == ActivityPub.fetch_public_activities(%{})
  968. assert [] == Pleroma.Notification.for_user(user2)
  969. assert [] ==
  970. ActivityPub.fetch_activities([user2.ap_id | User.following(user2)], %{
  971. user: user2
  972. })
  973. end
  974. end
  975. describe "approve" do
  976. test "approves a user" do
  977. user = insert(:user, approval_pending: true)
  978. assert true == user.approval_pending
  979. {:ok, user} = User.approve(user)
  980. assert false == user.approval_pending
  981. end
  982. test "approves a list of users" do
  983. unapproved_users = [
  984. insert(:user, approval_pending: true),
  985. insert(:user, approval_pending: true),
  986. insert(:user, approval_pending: true)
  987. ]
  988. {:ok, users} = User.approve(unapproved_users)
  989. assert Enum.count(users) == 3
  990. Enum.each(users, fn user ->
  991. assert false == user.approval_pending
  992. end)
  993. end
  994. end
  995. describe "delete" do
  996. setup do
  997. {:ok, user} = insert(:user) |> User.set_cache()
  998. [user: user]
  999. end
  1000. setup do: clear_config([:instance, :federating])
  1001. test ".delete_user_activities deletes all create activities", %{user: user} do
  1002. {:ok, activity} = CommonAPI.post(user, %{status: "2hu"})
  1003. User.delete_user_activities(user)
  1004. # TODO: Test removal favorites, repeats, delete activities.
  1005. refute Activity.get_by_id(activity.id)
  1006. end
  1007. test "it deactivates a user, all follow relationships and all activities", %{user: user} do
  1008. follower = insert(:user)
  1009. {:ok, follower} = User.follow(follower, user)
  1010. locked_user = insert(:user, name: "locked", locked: true)
  1011. {:ok, _} = User.follow(user, locked_user, :follow_pending)
  1012. object = insert(:note, user: user)
  1013. activity = insert(:note_activity, user: user, note: object)
  1014. object_two = insert(:note, user: follower)
  1015. activity_two = insert(:note_activity, user: follower, note: object_two)
  1016. {:ok, like} = CommonAPI.favorite(user, activity_two.id)
  1017. {:ok, like_two} = CommonAPI.favorite(follower, activity.id)
  1018. {:ok, repeat} = CommonAPI.repeat(activity_two.id, user)
  1019. {:ok, job} = User.delete(user)
  1020. {:ok, _user} = ObanHelpers.perform(job)
  1021. follower = User.get_cached_by_id(follower.id)
  1022. refute User.following?(follower, user)
  1023. assert %{deactivated: true} = User.get_by_id(user.id)
  1024. assert [] == User.get_follow_requests(locked_user)
  1025. user_activities =
  1026. user.ap_id
  1027. |> Activity.Queries.by_actor()
  1028. |> Repo.all()
  1029. |> Enum.map(fn act -> act.data["type"] end)
  1030. assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
  1031. refute Activity.get_by_id(activity.id)
  1032. refute Activity.get_by_id(like.id)
  1033. refute Activity.get_by_id(like_two.id)
  1034. refute Activity.get_by_id(repeat.id)
  1035. end
  1036. end
  1037. describe "delete/1 when confirmation is pending" do
  1038. setup do
  1039. user = insert(:user, confirmation_pending: true)
  1040. {:ok, user: user}
  1041. end
  1042. test "deletes user from database when activation required", %{user: user} do
  1043. clear_config([:instance, :account_activation_required], true)
  1044. {:ok, job} = User.delete(user)
  1045. {:ok, _} = ObanHelpers.perform(job)
  1046. refute User.get_cached_by_id(user.id)
  1047. refute User.get_by_id(user.id)
  1048. end
  1049. test "deactivates user when activation is not required", %{user: user} do
  1050. clear_config([:instance, :account_activation_required], false)
  1051. {:ok, job} = User.delete(user)
  1052. {:ok, _} = ObanHelpers.perform(job)
  1053. assert %{deactivated: true} = User.get_cached_by_id(user.id)
  1054. assert %{deactivated: true} = User.get_by_id(user.id)
  1055. end
  1056. end
  1057. test "delete/1 when approval is pending deletes the user" do
  1058. user = insert(:user, approval_pending: true)
  1059. {:ok, job} = User.delete(user)
  1060. {:ok, _} = ObanHelpers.perform(job)
  1061. refute User.get_cached_by_id(user.id)
  1062. refute User.get_by_id(user.id)
  1063. end
  1064. test "delete/1 purges a user when they wouldn't be fully deleted" do
  1065. user =
  1066. insert(:user, %{
  1067. bio: "eyy lmao",
  1068. name: "qqqqqqq",
  1069. password_hash: "pdfk2$1b3n159001",
  1070. keys: "RSA begin buplic key",
  1071. public_key: "--PRIVATE KEYE--",
  1072. avatar: %{"a" => "b"},
  1073. tags: ["qqqqq"],
  1074. banner: %{"a" => "b"},
  1075. background: %{"a" => "b"},
  1076. note_count: 9,
  1077. follower_count: 9,
  1078. following_count: 9001,
  1079. locked: true,
  1080. confirmation_pending: true,
  1081. password_reset_pending: true,
  1082. approval_pending: true,
  1083. registration_reason: "ahhhhh",
  1084. confirmation_token: "qqqq",
  1085. domain_blocks: ["lain.com"],
  1086. deactivated: true,
  1087. ap_enabled: true,
  1088. is_moderator: true,
  1089. is_admin: true,
  1090. mastofe_settings: %{"a" => "b"},
  1091. mascot: %{"a" => "b"},
  1092. emoji: %{"a" => "b"},
  1093. pleroma_settings_store: %{"q" => "x"},
  1094. fields: [%{"gg" => "qq"}],
  1095. raw_fields: [%{"gg" => "qq"}],
  1096. discoverable: true,
  1097. also_known_as: ["https://lol.olo/users/loll"]
  1098. })
  1099. {:ok, job} = User.delete(user)
  1100. {:ok, _} = ObanHelpers.perform(job)
  1101. user = User.get_by_id(user.id)
  1102. assert %User{
  1103. bio: "",
  1104. raw_bio: nil,
  1105. email: nil,
  1106. name: nil,
  1107. password_hash: nil,
  1108. keys: nil,
  1109. public_key: nil,
  1110. avatar: %{},
  1111. tags: [],
  1112. last_refreshed_at: nil,
  1113. last_digest_emailed_at: nil,
  1114. banner: %{},
  1115. background: %{},
  1116. note_count: 0,
  1117. follower_count: 0,
  1118. following_count: 0,
  1119. locked: false,
  1120. confirmation_pending: false,
  1121. password_reset_pending: false,
  1122. approval_pending: false,
  1123. registration_reason: nil,
  1124. confirmation_token: nil,
  1125. domain_blocks: [],
  1126. deactivated: true,
  1127. ap_enabled: false,
  1128. is_moderator: false,
  1129. is_admin: false,
  1130. mastofe_settings: nil,
  1131. mascot: nil,
  1132. emoji: %{},
  1133. pleroma_settings_store: %{},
  1134. fields: [],
  1135. raw_fields: [],
  1136. discoverable: false,
  1137. also_known_as: []
  1138. } = user
  1139. end
  1140. test "get_public_key_for_ap_id fetches a user that's not in the db" do
  1141. assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
  1142. end
  1143. describe "per-user rich-text filtering" do
  1144. test "html_filter_policy returns default policies, when rich-text is enabled" do
  1145. user = insert(:user)
  1146. assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
  1147. end
  1148. test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
  1149. user = insert(:user, no_rich_text: true)
  1150. assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
  1151. end
  1152. end
  1153. describe "caching" do
  1154. test "invalidate_cache works" do
  1155. user = insert(:user)
  1156. User.set_cache(user)
  1157. User.invalidate_cache(user)
  1158. {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1159. {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
  1160. end
  1161. test "User.delete() plugs any possible zombie objects" do
  1162. user = insert(:user)
  1163. {:ok, job} = User.delete(user)
  1164. {:ok, _} = ObanHelpers.perform(job)
  1165. {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1166. assert cached_user != user
  1167. {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
  1168. assert cached_user != user
  1169. end
  1170. end
  1171. describe "account_status/1" do
  1172. setup do: clear_config([:instance, :account_activation_required])
  1173. test "return confirmation_pending for unconfirm user" do
  1174. Pleroma.Config.put([:instance, :account_activation_required], true)
  1175. user = insert(:user, confirmation_pending: true)
  1176. assert User.account_status(user) == :confirmation_pending
  1177. end
  1178. test "return active for confirmed user" do
  1179. Pleroma.Config.put([:instance, :account_activation_required], true)
  1180. user = insert(:user, confirmation_pending: false)
  1181. assert User.account_status(user) == :active
  1182. end
  1183. test "return active for remote user" do
  1184. user = insert(:user, local: false)
  1185. assert User.account_status(user) == :active
  1186. end
  1187. test "returns :password_reset_pending for user with reset password" do
  1188. user = insert(:user, password_reset_pending: true)
  1189. assert User.account_status(user) == :password_reset_pending
  1190. end
  1191. test "returns :deactivated for deactivated user" do
  1192. user = insert(:user, local: true, confirmation_pending: false, deactivated: true)
  1193. assert User.account_status(user) == :deactivated
  1194. end
  1195. test "returns :approval_pending for unapproved user" do
  1196. user = insert(:user, local: true, approval_pending: true)
  1197. assert User.account_status(user) == :approval_pending
  1198. user = insert(:user, local: true, confirmation_pending: true, approval_pending: true)
  1199. assert User.account_status(user) == :approval_pending
  1200. end
  1201. end
  1202. describe "superuser?/1" do
  1203. test "returns false for unprivileged users" do
  1204. user = insert(:user, local: true)
  1205. refute User.superuser?(user)
  1206. end
  1207. test "returns false for remote users" do
  1208. user = insert(:user, local: false)
  1209. remote_admin_user = insert(:user, local: false, is_admin: true)
  1210. refute User.superuser?(user)
  1211. refute User.superuser?(remote_admin_user)
  1212. end
  1213. test "returns true for local moderators" do
  1214. user = insert(:user, local: true, is_moderator: true)
  1215. assert User.superuser?(user)
  1216. end
  1217. test "returns true for local admins" do
  1218. user = insert(:user, local: true, is_admin: true)
  1219. assert User.superuser?(user)
  1220. end
  1221. end
  1222. describe "invisible?/1" do
  1223. test "returns true for an invisible user" do
  1224. user = insert(:user, local: true, invisible: true)
  1225. assert User.invisible?(user)
  1226. end
  1227. test "returns false for a non-invisible user" do
  1228. user = insert(:user, local: true)
  1229. refute User.invisible?(user)
  1230. end
  1231. end
  1232. describe "visible_for/2" do
  1233. test "returns true when the account is itself" do
  1234. user = insert(:user, local: true)
  1235. assert User.visible_for(user, user) == :visible
  1236. end
  1237. test "returns false when the account is unconfirmed and confirmation is required" do
  1238. Pleroma.Config.put([:instance, :account_activation_required], true)
  1239. user = insert(:user, local: true, confirmation_pending: true)
  1240. other_user = insert(:user, local: true)
  1241. refute User.visible_for(user, other_user) == :visible
  1242. end
  1243. test "returns true when the account is unconfirmed and confirmation is required but the account is remote" do
  1244. Pleroma.Config.put([:instance, :account_activation_required], true)
  1245. user = insert(:user, local: false, confirmation_pending: true)
  1246. other_user = insert(:user, local: true)
  1247. assert User.visible_for(user, other_user) == :visible
  1248. end
  1249. test "returns true when the account is unconfirmed and confirmation is not required" do
  1250. user = insert(:user, local: true, confirmation_pending: true)
  1251. other_user = insert(:user, local: true)
  1252. assert User.visible_for(user, other_user) == :visible
  1253. end
  1254. test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do
  1255. Pleroma.Config.put([:instance, :account_activation_required], true)
  1256. user = insert(:user, local: true, confirmation_pending: true)
  1257. other_user = insert(:user, local: true, is_admin: true)
  1258. assert User.visible_for(user, other_user) == :visible
  1259. end
  1260. end
  1261. describe "parse_bio/2" do
  1262. test "preserves hosts in user links text" do
  1263. remote_user = insert(:user, local: false, nickname: "nick@domain.com")
  1264. user = insert(:user)
  1265. bio = "A.k.a. @nick@domain.com"
  1266. expected_text =
  1267. ~s(A.k.a. <span class="h-card"><a class="u-url mention" data-user="#{remote_user.id}" href="#{
  1268. remote_user.ap_id
  1269. }" rel="ugc">@<span>nick@domain.com</span></a></span>)
  1270. assert expected_text == User.parse_bio(bio, user)
  1271. end
  1272. test "Adds rel=me on linkbacked urls" do
  1273. user = insert(:user, ap_id: "https://social.example.org/users/lain")
  1274. bio = "http://example.com/rel_me/null"
  1275. expected_text = "<a href=\"#{bio}\">#{bio}</a>"
  1276. assert expected_text == User.parse_bio(bio, user)
  1277. bio = "http://example.com/rel_me/link"
  1278. expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
  1279. assert expected_text == User.parse_bio(bio, user)
  1280. bio = "http://example.com/rel_me/anchor"
  1281. expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
  1282. assert expected_text == User.parse_bio(bio, user)
  1283. end
  1284. end
  1285. test "follower count is updated when a follower is blocked" do
  1286. user = insert(:user)
  1287. follower = insert(:user)
  1288. follower2 = insert(:user)
  1289. follower3 = insert(:user)
  1290. {:ok, follower} = User.follow(follower, user)
  1291. {:ok, _follower2} = User.follow(follower2, user)
  1292. {:ok, _follower3} = User.follow(follower3, user)
  1293. {:ok, _user_relationship} = User.block(user, follower)
  1294. user = refresh_record(user)
  1295. assert user.follower_count == 2
  1296. end
  1297. describe "list_inactive_users_query/1" do
  1298. defp days_ago(days) do
  1299. NaiveDateTime.add(
  1300. NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
  1301. -days * 60 * 60 * 24,
  1302. :second
  1303. )
  1304. end
  1305. test "Users are inactive by default" do
  1306. total = 10
  1307. users =
  1308. Enum.map(1..total, fn _ ->
  1309. insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
  1310. end)
  1311. inactive_users_ids =
  1312. Pleroma.User.list_inactive_users_query()
  1313. |> Pleroma.Repo.all()
  1314. |> Enum.map(& &1.id)
  1315. Enum.each(users, fn user ->
  1316. assert user.id in inactive_users_ids
  1317. end)
  1318. end
  1319. test "Only includes users who has no recent activity" do
  1320. total = 10
  1321. users =
  1322. Enum.map(1..total, fn _ ->
  1323. insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
  1324. end)
  1325. {inactive, active} = Enum.split(users, trunc(total / 2))
  1326. Enum.map(active, fn user ->
  1327. to = Enum.random(users -- [user])
  1328. {:ok, _} =
  1329. CommonAPI.post(user, %{
  1330. status: "hey @#{to.nickname}"
  1331. })
  1332. end)
  1333. inactive_users_ids =
  1334. Pleroma.User.list_inactive_users_query()
  1335. |> Pleroma.Repo.all()
  1336. |> Enum.map(& &1.id)
  1337. Enum.each(active, fn user ->
  1338. refute user.id in inactive_users_ids
  1339. end)
  1340. Enum.each(inactive, fn user ->
  1341. assert user.id in inactive_users_ids
  1342. end)
  1343. end
  1344. test "Only includes users with no read notifications" do
  1345. total = 10
  1346. users =
  1347. Enum.map(1..total, fn _ ->
  1348. insert(:user, last_digest_emailed_at: days_ago(20), deactivated: false)
  1349. end)
  1350. [sender | recipients] = users
  1351. {inactive, active} = Enum.split(recipients, trunc(total / 2))
  1352. Enum.each(recipients, fn to ->
  1353. {:ok, _} =
  1354. CommonAPI.post(sender, %{
  1355. status: "hey @#{to.nickname}"
  1356. })
  1357. {:ok, _} =
  1358. CommonAPI.post(sender, %{
  1359. status: "hey again @#{to.nickname}"
  1360. })
  1361. end)
  1362. Enum.each(active, fn user ->
  1363. [n1, _n2] = Pleroma.Notification.for_user(user)
  1364. {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
  1365. end)
  1366. inactive_users_ids =
  1367. Pleroma.User.list_inactive_users_query()
  1368. |> Pleroma.Repo.all()
  1369. |> Enum.map(& &1.id)
  1370. Enum.each(active, fn user ->
  1371. refute user.id in inactive_users_ids
  1372. end)
  1373. Enum.each(inactive, fn user ->
  1374. assert user.id in inactive_users_ids
  1375. end)
  1376. end
  1377. end
  1378. describe "toggle_confirmation/1" do
  1379. test "if user is confirmed" do
  1380. user = insert(:user, confirmation_pending: false)
  1381. {:ok, user} = User.toggle_confirmation(user)
  1382. assert user.confirmation_pending
  1383. assert user.confirmation_token
  1384. end
  1385. test "if user is unconfirmed" do
  1386. user = insert(:user, confirmation_pending: true, confirmation_token: "some token")
  1387. {:ok, user} = User.toggle_confirmation(user)
  1388. refute user.confirmation_pending
  1389. refute user.confirmation_token
  1390. end
  1391. end
  1392. describe "ensure_keys_present" do
  1393. test "it creates keys for a user and stores them in info" do
  1394. user = insert(:user)
  1395. refute is_binary(user.keys)
  1396. {:ok, user} = User.ensure_keys_present(user)
  1397. assert is_binary(user.keys)
  1398. end
  1399. test "it doesn't create keys if there already are some" do
  1400. user = insert(:user, keys: "xxx")
  1401. {:ok, user} = User.ensure_keys_present(user)
  1402. assert user.keys == "xxx"
  1403. end
  1404. end
  1405. describe "get_ap_ids_by_nicknames" do
  1406. test "it returns a list of AP ids for a given set of nicknames" do
  1407. user = insert(:user)
  1408. user_two = insert(:user)
  1409. ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
  1410. assert length(ap_ids) == 2
  1411. assert user.ap_id in ap_ids
  1412. assert user_two.ap_id in ap_ids
  1413. end
  1414. end
  1415. describe "sync followers count" do
  1416. setup do
  1417. user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
  1418. user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
  1419. insert(:user, local: true)
  1420. insert(:user, local: false, deactivated: true)
  1421. {:ok, user1: user1, user2: user2}
  1422. end
  1423. test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
  1424. [fdb_user1] = User.external_users(limit: 1)
  1425. assert fdb_user1.ap_id
  1426. assert fdb_user1.ap_id == user1.ap_id
  1427. assert fdb_user1.id == user1.id
  1428. [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
  1429. assert fdb_user2.ap_id
  1430. assert fdb_user2.ap_id == user2.ap_id
  1431. assert fdb_user2.id == user2.id
  1432. assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
  1433. end
  1434. end
  1435. describe "is_internal_user?/1" do
  1436. test "non-internal user returns false" do
  1437. user = insert(:user)
  1438. refute User.is_internal_user?(user)
  1439. end
  1440. test "user with no nickname returns true" do
  1441. user = insert(:user, %{nickname: nil})
  1442. assert User.is_internal_user?(user)
  1443. end
  1444. test "user with internal-prefixed nickname returns true" do
  1445. user = insert(:user, %{nickname: "internal.test"})
  1446. assert User.is_internal_user?(user)
  1447. end
  1448. end
  1449. describe "update_and_set_cache/1" do
  1450. test "returns error when user is stale instead Ecto.StaleEntryError" do
  1451. user = insert(:user)
  1452. changeset = Ecto.Changeset.change(user, bio: "test")
  1453. Repo.delete(user)
  1454. assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
  1455. User.update_and_set_cache(changeset)
  1456. end
  1457. test "performs update cache if user updated" do
  1458. user = insert(:user)
  1459. assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1460. changeset = Ecto.Changeset.change(user, bio: "test-bio")
  1461. assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
  1462. assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1463. assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
  1464. end
  1465. end
  1466. describe "following/followers synchronization" do
  1467. setup do: clear_config([:instance, :external_user_synchronization])
  1468. test "updates the counters normally on following/getting a follow when disabled" do
  1469. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1470. user = insert(:user)
  1471. other_user =
  1472. insert(:user,
  1473. local: false,
  1474. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1475. following_address: "http://localhost:4001/users/masto_closed/following",
  1476. ap_enabled: true
  1477. )
  1478. assert other_user.following_count == 0
  1479. assert other_user.follower_count == 0
  1480. {:ok, user} = Pleroma.User.follow(user, other_user)
  1481. other_user = Pleroma.User.get_by_id(other_user.id)
  1482. assert user.following_count == 1
  1483. assert other_user.follower_count == 1
  1484. end
  1485. test "syncronizes the counters with the remote instance for the followed when enabled" do
  1486. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1487. user = insert(:user)
  1488. other_user =
  1489. insert(:user,
  1490. local: false,
  1491. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1492. following_address: "http://localhost:4001/users/masto_closed/following",
  1493. ap_enabled: true
  1494. )
  1495. assert other_user.following_count == 0
  1496. assert other_user.follower_count == 0
  1497. Pleroma.Config.put([:instance, :external_user_synchronization], true)
  1498. {:ok, _user} = User.follow(user, other_user)
  1499. other_user = User.get_by_id(other_user.id)
  1500. assert other_user.follower_count == 437
  1501. end
  1502. test "syncronizes the counters with the remote instance for the follower when enabled" do
  1503. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1504. user = insert(:user)
  1505. other_user =
  1506. insert(:user,
  1507. local: false,
  1508. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1509. following_address: "http://localhost:4001/users/masto_closed/following",
  1510. ap_enabled: true
  1511. )
  1512. assert other_user.following_count == 0
  1513. assert other_user.follower_count == 0
  1514. Pleroma.Config.put([:instance, :external_user_synchronization], true)
  1515. {:ok, other_user} = User.follow(other_user, user)
  1516. assert other_user.following_count == 152
  1517. end
  1518. end
  1519. describe "change_email/2" do
  1520. setup do
  1521. [user: insert(:user)]
  1522. end
  1523. test "blank email returns error", %{user: user} do
  1524. assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
  1525. assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
  1526. end
  1527. test "non unique email returns error", %{user: user} do
  1528. %{email: email} = insert(:user)
  1529. assert {:error, %{errors: [email: {"has already been taken", _}]}} =
  1530. User.change_email(user, email)
  1531. end
  1532. test "invalid email returns error", %{user: user} do
  1533. assert {:error, %{errors: [email: {"has invalid format", _}]}} =
  1534. User.change_email(user, "cofe")
  1535. end
  1536. test "changes email", %{user: user} do
  1537. assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
  1538. end
  1539. end
  1540. describe "get_cached_by_nickname_or_id" do
  1541. setup do
  1542. local_user = insert(:user)
  1543. remote_user = insert(:user, nickname: "nickname@example.com", local: false)
  1544. [local_user: local_user, remote_user: remote_user]
  1545. end
  1546. setup do: clear_config([:instance, :limit_to_local_content])
  1547. test "allows getting remote users by id no matter what :limit_to_local_content is set to", %{
  1548. remote_user: remote_user
  1549. } do
  1550. Pleroma.Config.put([:instance, :limit_to_local_content], false)
  1551. assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
  1552. Pleroma.Config.put([:instance, :limit_to_local_content], true)
  1553. assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
  1554. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  1555. assert %User{} = User.get_cached_by_nickname_or_id(remote_user.id)
  1556. end
  1557. test "disallows getting remote users by nickname without authentication when :limit_to_local_content is set to :unauthenticated",
  1558. %{remote_user: remote_user} do
  1559. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  1560. assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
  1561. end
  1562. test "allows getting remote users by nickname with authentication when :limit_to_local_content is set to :unauthenticated",
  1563. %{remote_user: remote_user, local_user: local_user} do
  1564. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  1565. assert %User{} = User.get_cached_by_nickname_or_id(remote_user.nickname, for: local_user)
  1566. end
  1567. test "disallows getting remote users by nickname when :limit_to_local_content is set to true",
  1568. %{remote_user: remote_user} do
  1569. Pleroma.Config.put([:instance, :limit_to_local_content], true)
  1570. assert nil == User.get_cached_by_nickname_or_id(remote_user.nickname)
  1571. end
  1572. test "allows getting local users by nickname no matter what :limit_to_local_content is set to",
  1573. %{local_user: local_user} do
  1574. Pleroma.Config.put([:instance, :limit_to_local_content], false)
  1575. assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
  1576. Pleroma.Config.put([:instance, :limit_to_local_content], true)
  1577. assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
  1578. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  1579. assert %User{} = User.get_cached_by_nickname_or_id(local_user.nickname)
  1580. end
  1581. end
  1582. describe "update_email_notifications/2" do
  1583. setup do
  1584. user = insert(:user, email_notifications: %{"digest" => true})
  1585. {:ok, user: user}
  1586. end
  1587. test "Notifications are updated", %{user: user} do
  1588. true = user.email_notifications["digest"]
  1589. assert {:ok, result} = User.update_email_notifications(user, %{"digest" => false})
  1590. assert result.email_notifications["digest"] == false
  1591. end
  1592. end
  1593. test "avatar fallback" do
  1594. user = insert(:user)
  1595. assert User.avatar_url(user) =~ "/images/avi.png"
  1596. clear_config([:assets, :default_user_avatar], "avatar.png")
  1597. user = User.get_cached_by_nickname_or_id(user.nickname)
  1598. assert User.avatar_url(user) =~ "avatar.png"
  1599. assert User.avatar_url(user, no_default: true) == nil
  1600. end
  1601. end