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.

1729 lines
51KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2019 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 Mock
  16. import Pleroma.Factory
  17. setup_all do
  18. Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
  19. :ok
  20. end
  21. clear_config([:instance, :account_activation_required])
  22. describe "when tags are nil" do
  23. test "tagging a user" do
  24. user = insert(:user, %{tags: nil})
  25. user = User.tag(user, ["cool", "dude"])
  26. assert "cool" in user.tags
  27. assert "dude" in user.tags
  28. end
  29. test "untagging a user" do
  30. user = insert(:user, %{tags: nil})
  31. user = User.untag(user, ["cool", "dude"])
  32. assert user.tags == []
  33. end
  34. end
  35. test "ap_id returns the activity pub id for the user" do
  36. user = UserBuilder.build()
  37. expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
  38. assert expected_ap_id == User.ap_id(user)
  39. end
  40. test "ap_followers returns the followers collection for the user" do
  41. user = UserBuilder.build()
  42. expected_followers_collection = "#{User.ap_id(user)}/followers"
  43. assert expected_followers_collection == User.ap_followers(user)
  44. end
  45. test "ap_following returns the following collection for the user" do
  46. user = UserBuilder.build()
  47. expected_followers_collection = "#{User.ap_id(user)}/following"
  48. assert expected_followers_collection == User.ap_following(user)
  49. end
  50. test "returns all pending follow requests" do
  51. unlocked = insert(:user)
  52. locked = insert(:user, %{info: %{locked: true}})
  53. follower = insert(:user)
  54. CommonAPI.follow(follower, unlocked)
  55. CommonAPI.follow(follower, locked)
  56. assert [] = User.get_follow_requests(unlocked)
  57. assert [activity] = User.get_follow_requests(locked)
  58. assert activity
  59. end
  60. test "doesn't return already accepted or duplicate follow requests" do
  61. locked = insert(:user, %{info: %{locked: true}})
  62. pending_follower = insert(:user)
  63. accepted_follower = insert(:user)
  64. CommonAPI.follow(pending_follower, locked)
  65. CommonAPI.follow(pending_follower, locked)
  66. CommonAPI.follow(accepted_follower, locked)
  67. User.follow(accepted_follower, locked)
  68. assert [activity] = User.get_follow_requests(locked)
  69. assert activity
  70. end
  71. test "clears follow requests when requester is blocked" do
  72. followed = insert(:user, %{info: %{locked: true}})
  73. follower = insert(:user)
  74. CommonAPI.follow(follower, followed)
  75. assert [_activity] = User.get_follow_requests(followed)
  76. {:ok, _follower} = User.block(followed, follower)
  77. assert [] = User.get_follow_requests(followed)
  78. end
  79. test "follow_all follows mutliple users" do
  80. user = insert(:user)
  81. followed_zero = insert(:user)
  82. followed_one = insert(:user)
  83. followed_two = insert(:user)
  84. blocked = insert(:user)
  85. not_followed = insert(:user)
  86. reverse_blocked = insert(:user)
  87. {:ok, user} = User.block(user, blocked)
  88. {:ok, reverse_blocked} = User.block(reverse_blocked, user)
  89. {:ok, user} = User.follow(user, followed_zero)
  90. {:ok, user} = User.follow_all(user, [followed_one, followed_two, blocked, reverse_blocked])
  91. assert User.following?(user, followed_one)
  92. assert User.following?(user, followed_two)
  93. assert User.following?(user, followed_zero)
  94. refute User.following?(user, not_followed)
  95. refute User.following?(user, blocked)
  96. refute User.following?(user, reverse_blocked)
  97. end
  98. test "follow_all follows mutliple users without duplicating" do
  99. user = insert(:user)
  100. followed_zero = insert(:user)
  101. followed_one = insert(:user)
  102. followed_two = insert(:user)
  103. {:ok, user} = User.follow_all(user, [followed_zero, followed_one])
  104. assert length(user.following) == 3
  105. {:ok, user} = User.follow_all(user, [followed_one, followed_two])
  106. assert length(user.following) == 4
  107. end
  108. test "follow takes a user and another user" do
  109. user = insert(:user)
  110. followed = insert(:user)
  111. {:ok, user} = User.follow(user, followed)
  112. user = User.get_cached_by_id(user.id)
  113. followed = User.get_cached_by_ap_id(followed.ap_id)
  114. assert followed.info.follower_count == 1
  115. assert User.ap_followers(followed) in user.following
  116. end
  117. test "can't follow a deactivated users" do
  118. user = insert(:user)
  119. followed = insert(:user, info: %{deactivated: true})
  120. {:error, _} = User.follow(user, followed)
  121. end
  122. test "can't follow a user who blocked us" do
  123. blocker = insert(:user)
  124. blockee = insert(:user)
  125. {:ok, blocker} = User.block(blocker, blockee)
  126. {:error, _} = User.follow(blockee, blocker)
  127. end
  128. test "can't subscribe to a user who blocked us" do
  129. blocker = insert(:user)
  130. blocked = insert(:user)
  131. {:ok, blocker} = User.block(blocker, blocked)
  132. {:error, _} = User.subscribe(blocked, blocker)
  133. end
  134. test "local users do not automatically follow local locked accounts" do
  135. follower = insert(:user, info: %{locked: true})
  136. followed = insert(:user, info: %{locked: true})
  137. {:ok, follower} = User.maybe_direct_follow(follower, followed)
  138. refute User.following?(follower, followed)
  139. end
  140. # This is a somewhat useless test.
  141. # test "following a remote user will ensure a websub subscription is present" do
  142. # user = insert(:user)
  143. # {:ok, followed} = OStatus.make_user("shp@social.heldscal.la")
  144. # assert followed.local == false
  145. # {:ok, user} = User.follow(user, followed)
  146. # assert User.ap_followers(followed) in user.following
  147. # query = from w in WebsubClientSubscription,
  148. # where: w.topic == ^followed.info["topic"]
  149. # websub = Repo.one(query)
  150. # assert websub
  151. # end
  152. describe "unfollow/2" do
  153. setup do
  154. setting = Pleroma.Config.get([:instance, :external_user_synchronization])
  155. on_exit(fn ->
  156. Pleroma.Config.put([:instance, :external_user_synchronization], setting)
  157. end)
  158. :ok
  159. end
  160. test "unfollow with syncronizes external user" do
  161. Pleroma.Config.put([:instance, :external_user_synchronization], true)
  162. followed =
  163. insert(:user,
  164. nickname: "fuser1",
  165. follower_address: "http://localhost:4001/users/fuser1/followers",
  166. following_address: "http://localhost:4001/users/fuser1/following",
  167. ap_id: "http://localhost:4001/users/fuser1"
  168. )
  169. user =
  170. insert(:user, %{
  171. local: false,
  172. nickname: "fuser2",
  173. ap_id: "http://localhost:4001/users/fuser2",
  174. follower_address: "http://localhost:4001/users/fuser2/followers",
  175. following_address: "http://localhost:4001/users/fuser2/following",
  176. following: [User.ap_followers(followed)]
  177. })
  178. {:ok, user, _activity} = User.unfollow(user, followed)
  179. user = User.get_cached_by_id(user.id)
  180. assert user.following == []
  181. end
  182. test "unfollow takes a user and another user" do
  183. followed = insert(:user)
  184. user = insert(:user, %{following: [User.ap_followers(followed)]})
  185. {:ok, user, _activity} = User.unfollow(user, followed)
  186. user = User.get_cached_by_id(user.id)
  187. assert user.following == []
  188. end
  189. test "unfollow doesn't unfollow yourself" do
  190. user = insert(:user)
  191. {:error, _} = User.unfollow(user, user)
  192. user = User.get_cached_by_id(user.id)
  193. assert user.following == [user.ap_id]
  194. end
  195. end
  196. test "test if a user is following another user" do
  197. followed = insert(:user)
  198. user = insert(:user, %{following: [User.ap_followers(followed)]})
  199. assert User.following?(user, followed)
  200. refute User.following?(followed, user)
  201. end
  202. test "fetches correct profile for nickname beginning with number" do
  203. # Use old-style integer ID to try to reproduce the problem
  204. user = insert(:user, %{id: 1080})
  205. user_with_numbers = insert(:user, %{nickname: "#{user.id}garbage"})
  206. assert user_with_numbers == User.get_cached_by_nickname_or_id(user_with_numbers.nickname)
  207. end
  208. describe "user registration" do
  209. @full_user_data %{
  210. bio: "A guy",
  211. name: "my name",
  212. nickname: "nick",
  213. password: "test",
  214. password_confirmation: "test",
  215. email: "email@example.com"
  216. }
  217. clear_config([:instance, :autofollowed_nicknames])
  218. clear_config([:instance, :welcome_message])
  219. clear_config([:instance, :welcome_user_nickname])
  220. test "it autofollows accounts that are set for it" do
  221. user = insert(:user)
  222. remote_user = insert(:user, %{local: false})
  223. Pleroma.Config.put([:instance, :autofollowed_nicknames], [
  224. user.nickname,
  225. remote_user.nickname
  226. ])
  227. cng = User.register_changeset(%User{}, @full_user_data)
  228. {:ok, registered_user} = User.register(cng)
  229. assert User.following?(registered_user, user)
  230. refute User.following?(registered_user, remote_user)
  231. end
  232. test "it sends a welcome message if it is set" do
  233. welcome_user = insert(:user)
  234. Pleroma.Config.put([:instance, :welcome_user_nickname], welcome_user.nickname)
  235. Pleroma.Config.put([:instance, :welcome_message], "Hello, this is a cool site")
  236. cng = User.register_changeset(%User{}, @full_user_data)
  237. {:ok, registered_user} = User.register(cng)
  238. activity = Repo.one(Pleroma.Activity)
  239. assert registered_user.ap_id in activity.recipients
  240. assert Object.normalize(activity).data["content"] =~ "cool site"
  241. assert activity.actor == welcome_user.ap_id
  242. end
  243. test "it requires an email, name, nickname and password, bio is optional" do
  244. @full_user_data
  245. |> Map.keys()
  246. |> Enum.each(fn key ->
  247. params = Map.delete(@full_user_data, key)
  248. changeset = User.register_changeset(%User{}, params)
  249. assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
  250. end)
  251. end
  252. test "it restricts certain nicknames" do
  253. [restricted_name | _] = Pleroma.Config.get([User, :restricted_nicknames])
  254. assert is_bitstring(restricted_name)
  255. params =
  256. @full_user_data
  257. |> Map.put(:nickname, restricted_name)
  258. changeset = User.register_changeset(%User{}, params)
  259. refute changeset.valid?
  260. end
  261. test "it sets the password_hash, ap_id and following fields" do
  262. changeset = User.register_changeset(%User{}, @full_user_data)
  263. assert changeset.valid?
  264. assert is_binary(changeset.changes[:password_hash])
  265. assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
  266. assert changeset.changes[:following] == [
  267. User.ap_followers(%User{nickname: @full_user_data.nickname})
  268. ]
  269. assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
  270. end
  271. test "it ensures info is not nil" do
  272. changeset = User.register_changeset(%User{}, @full_user_data)
  273. assert changeset.valid?
  274. {:ok, user} =
  275. changeset
  276. |> Repo.insert()
  277. refute is_nil(user.info)
  278. end
  279. end
  280. describe "user registration, with :account_activation_required" do
  281. @full_user_data %{
  282. bio: "A guy",
  283. name: "my name",
  284. nickname: "nick",
  285. password: "test",
  286. password_confirmation: "test",
  287. email: "email@example.com"
  288. }
  289. clear_config([:instance, :account_activation_required]) do
  290. Pleroma.Config.put([:instance, :account_activation_required], true)
  291. end
  292. test "it creates unconfirmed user" do
  293. changeset = User.register_changeset(%User{}, @full_user_data)
  294. assert changeset.valid?
  295. {:ok, user} = Repo.insert(changeset)
  296. assert user.info.confirmation_pending
  297. assert user.info.confirmation_token
  298. end
  299. test "it creates confirmed user if :confirmed option is given" do
  300. changeset = User.register_changeset(%User{}, @full_user_data, need_confirmation: false)
  301. assert changeset.valid?
  302. {:ok, user} = Repo.insert(changeset)
  303. refute user.info.confirmation_pending
  304. refute user.info.confirmation_token
  305. end
  306. end
  307. describe "get_or_fetch/1" do
  308. test "gets an existing user by nickname" do
  309. user = insert(:user)
  310. {:ok, fetched_user} = User.get_or_fetch(user.nickname)
  311. assert user == fetched_user
  312. end
  313. test "gets an existing user by ap_id" do
  314. ap_id = "http://mastodon.example.org/users/admin"
  315. user =
  316. insert(
  317. :user,
  318. local: false,
  319. nickname: "admin@mastodon.example.org",
  320. ap_id: ap_id,
  321. info: %{}
  322. )
  323. {:ok, fetched_user} = User.get_or_fetch(ap_id)
  324. freshed_user = refresh_record(user)
  325. assert freshed_user == fetched_user
  326. end
  327. end
  328. describe "fetching a user from nickname or trying to build one" do
  329. test "gets an existing user" do
  330. user = insert(:user)
  331. {:ok, fetched_user} = User.get_or_fetch_by_nickname(user.nickname)
  332. assert user == fetched_user
  333. end
  334. test "gets an existing user, case insensitive" do
  335. user = insert(:user, nickname: "nick")
  336. {:ok, fetched_user} = User.get_or_fetch_by_nickname("NICK")
  337. assert user == fetched_user
  338. end
  339. test "gets an existing user by fully qualified nickname" do
  340. user = insert(:user)
  341. {:ok, fetched_user} =
  342. User.get_or_fetch_by_nickname(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
  343. assert user == fetched_user
  344. end
  345. test "gets an existing user by fully qualified nickname, case insensitive" do
  346. user = insert(:user, nickname: "nick")
  347. casing_altered_fqn = String.upcase(user.nickname <> "@" <> Pleroma.Web.Endpoint.host())
  348. {:ok, fetched_user} = User.get_or_fetch_by_nickname(casing_altered_fqn)
  349. assert user == fetched_user
  350. end
  351. test "fetches an external user via ostatus if no user exists" do
  352. {:ok, fetched_user} = User.get_or_fetch_by_nickname("shp@social.heldscal.la")
  353. assert fetched_user.nickname == "shp@social.heldscal.la"
  354. end
  355. test "returns nil if no user could be fetched" do
  356. {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
  357. assert fetched_user == "not found nonexistant@social.heldscal.la"
  358. end
  359. test "returns nil for nonexistant local user" do
  360. {:error, fetched_user} = User.get_or_fetch_by_nickname("nonexistant")
  361. assert fetched_user == "not found nonexistant"
  362. end
  363. test "updates an existing user, if stale" do
  364. a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
  365. orig_user =
  366. insert(
  367. :user,
  368. local: false,
  369. nickname: "admin@mastodon.example.org",
  370. ap_id: "http://mastodon.example.org/users/admin",
  371. last_refreshed_at: a_week_ago,
  372. info: %{}
  373. )
  374. assert orig_user.last_refreshed_at == a_week_ago
  375. {:ok, user} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
  376. assert user.info.source_data["endpoints"]
  377. refute user.last_refreshed_at == orig_user.last_refreshed_at
  378. end
  379. end
  380. test "returns an ap_id for a user" do
  381. user = insert(:user)
  382. assert User.ap_id(user) ==
  383. Pleroma.Web.Router.Helpers.o_status_url(
  384. Pleroma.Web.Endpoint,
  385. :feed_redirect,
  386. user.nickname
  387. )
  388. end
  389. test "returns an ap_followers link for a user" do
  390. user = insert(:user)
  391. assert User.ap_followers(user) ==
  392. Pleroma.Web.Router.Helpers.o_status_url(
  393. Pleroma.Web.Endpoint,
  394. :feed_redirect,
  395. user.nickname
  396. ) <> "/followers"
  397. end
  398. describe "remote user creation changeset" do
  399. @valid_remote %{
  400. bio: "hello",
  401. name: "Someone",
  402. nickname: "a@b.de",
  403. ap_id: "http...",
  404. info: %{some: "info"},
  405. avatar: %{some: "avatar"}
  406. }
  407. clear_config([:instance, :user_bio_length])
  408. clear_config([:instance, :user_name_length])
  409. test "it confirms validity" do
  410. cs = User.remote_user_creation(@valid_remote)
  411. assert cs.valid?
  412. end
  413. test "it sets the follower_adress" do
  414. cs = User.remote_user_creation(@valid_remote)
  415. # remote users get a fake local follower address
  416. assert cs.changes.follower_address ==
  417. User.ap_followers(%User{nickname: @valid_remote[:nickname]})
  418. end
  419. test "it enforces the fqn format for nicknames" do
  420. cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"})
  421. assert Ecto.Changeset.get_field(cs, :local) == false
  422. assert cs.changes.avatar
  423. refute cs.valid?
  424. end
  425. test "it has required fields" do
  426. [:name, :ap_id]
  427. |> Enum.each(fn field ->
  428. cs = User.remote_user_creation(Map.delete(@valid_remote, field))
  429. refute cs.valid?
  430. end)
  431. end
  432. end
  433. describe "followers and friends" do
  434. test "gets all followers for a given user" do
  435. user = insert(:user)
  436. follower_one = insert(:user)
  437. follower_two = insert(:user)
  438. not_follower = insert(:user)
  439. {:ok, follower_one} = User.follow(follower_one, user)
  440. {:ok, follower_two} = User.follow(follower_two, user)
  441. res = User.get_followers(user)
  442. assert Enum.member?(res, follower_one)
  443. assert Enum.member?(res, follower_two)
  444. refute Enum.member?(res, not_follower)
  445. end
  446. test "gets all friends (followed users) for a given user" do
  447. user = insert(:user)
  448. followed_one = insert(:user)
  449. followed_two = insert(:user)
  450. not_followed = insert(:user)
  451. {:ok, user} = User.follow(user, followed_one)
  452. {:ok, user} = User.follow(user, followed_two)
  453. res = User.get_friends(user)
  454. followed_one = User.get_cached_by_ap_id(followed_one.ap_id)
  455. followed_two = User.get_cached_by_ap_id(followed_two.ap_id)
  456. assert Enum.member?(res, followed_one)
  457. assert Enum.member?(res, followed_two)
  458. refute Enum.member?(res, not_followed)
  459. end
  460. end
  461. describe "updating note and follower count" do
  462. test "it sets the info->note_count property" do
  463. note = insert(:note)
  464. user = User.get_cached_by_ap_id(note.data["actor"])
  465. assert user.info.note_count == 0
  466. {:ok, user} = User.update_note_count(user)
  467. assert user.info.note_count == 1
  468. end
  469. test "it increases the info->note_count property" do
  470. note = insert(:note)
  471. user = User.get_cached_by_ap_id(note.data["actor"])
  472. assert user.info.note_count == 0
  473. {:ok, user} = User.increase_note_count(user)
  474. assert user.info.note_count == 1
  475. {:ok, user} = User.increase_note_count(user)
  476. assert user.info.note_count == 2
  477. end
  478. test "it decreases the info->note_count property" do
  479. note = insert(:note)
  480. user = User.get_cached_by_ap_id(note.data["actor"])
  481. assert user.info.note_count == 0
  482. {:ok, user} = User.increase_note_count(user)
  483. assert user.info.note_count == 1
  484. {:ok, user} = User.decrease_note_count(user)
  485. assert user.info.note_count == 0
  486. {:ok, user} = User.decrease_note_count(user)
  487. assert user.info.note_count == 0
  488. end
  489. test "it sets the info->follower_count property" do
  490. user = insert(:user)
  491. follower = insert(:user)
  492. User.follow(follower, user)
  493. assert user.info.follower_count == 0
  494. {:ok, user} = User.update_follower_count(user)
  495. assert user.info.follower_count == 1
  496. end
  497. end
  498. describe "remove duplicates from following list" do
  499. test "it removes duplicates" do
  500. user = insert(:user)
  501. follower = insert(:user)
  502. {:ok, %User{following: following} = follower} = User.follow(follower, user)
  503. assert length(following) == 2
  504. {:ok, follower} =
  505. follower
  506. |> User.update_changeset(%{following: following ++ following})
  507. |> Repo.update()
  508. assert length(follower.following) == 4
  509. {:ok, follower} = User.remove_duplicated_following(follower)
  510. assert length(follower.following) == 2
  511. end
  512. test "it does nothing when following is uniq" do
  513. user = insert(:user)
  514. follower = insert(:user)
  515. {:ok, follower} = User.follow(follower, user)
  516. assert length(follower.following) == 2
  517. {:ok, follower} = User.remove_duplicated_following(follower)
  518. assert length(follower.following) == 2
  519. end
  520. end
  521. describe "follow_import" do
  522. test "it imports user followings from list" do
  523. [user1, user2, user3] = insert_list(3, :user)
  524. identifiers = [
  525. user2.ap_id,
  526. user3.nickname
  527. ]
  528. {:ok, job} = User.follow_import(user1, identifiers)
  529. result = ObanHelpers.perform(job)
  530. assert is_list(result)
  531. assert result == [user2, user3]
  532. end
  533. end
  534. describe "mutes" do
  535. test "it mutes people" do
  536. user = insert(:user)
  537. muted_user = insert(:user)
  538. refute User.mutes?(user, muted_user)
  539. refute User.muted_notifications?(user, muted_user)
  540. {:ok, user} = User.mute(user, muted_user)
  541. assert User.mutes?(user, muted_user)
  542. assert User.muted_notifications?(user, muted_user)
  543. end
  544. test "it unmutes users" do
  545. user = insert(:user)
  546. muted_user = insert(:user)
  547. {:ok, user} = User.mute(user, muted_user)
  548. {:ok, user} = User.unmute(user, muted_user)
  549. refute User.mutes?(user, muted_user)
  550. refute User.muted_notifications?(user, muted_user)
  551. end
  552. test "it mutes user without notifications" do
  553. user = insert(:user)
  554. muted_user = insert(:user)
  555. refute User.mutes?(user, muted_user)
  556. refute User.muted_notifications?(user, muted_user)
  557. {:ok, user} = User.mute(user, muted_user, false)
  558. assert User.mutes?(user, muted_user)
  559. refute User.muted_notifications?(user, muted_user)
  560. end
  561. end
  562. describe "blocks" do
  563. test "it blocks people" do
  564. user = insert(:user)
  565. blocked_user = insert(:user)
  566. refute User.blocks?(user, blocked_user)
  567. {:ok, user} = User.block(user, blocked_user)
  568. assert User.blocks?(user, blocked_user)
  569. end
  570. test "it unblocks users" do
  571. user = insert(:user)
  572. blocked_user = insert(:user)
  573. {:ok, user} = User.block(user, blocked_user)
  574. {:ok, user} = User.unblock(user, blocked_user)
  575. refute User.blocks?(user, blocked_user)
  576. end
  577. test "blocks tear down cyclical follow relationships" do
  578. blocker = insert(:user)
  579. blocked = insert(:user)
  580. {:ok, blocker} = User.follow(blocker, blocked)
  581. {:ok, blocked} = User.follow(blocked, blocker)
  582. assert User.following?(blocker, blocked)
  583. assert User.following?(blocked, blocker)
  584. {:ok, blocker} = User.block(blocker, blocked)
  585. blocked = User.get_cached_by_id(blocked.id)
  586. assert User.blocks?(blocker, blocked)
  587. refute User.following?(blocker, blocked)
  588. refute User.following?(blocked, blocker)
  589. end
  590. test "blocks tear down blocker->blocked follow relationships" do
  591. blocker = insert(:user)
  592. blocked = insert(:user)
  593. {:ok, blocker} = User.follow(blocker, blocked)
  594. assert User.following?(blocker, blocked)
  595. refute User.following?(blocked, blocker)
  596. {:ok, blocker} = User.block(blocker, blocked)
  597. blocked = User.get_cached_by_id(blocked.id)
  598. assert User.blocks?(blocker, blocked)
  599. refute User.following?(blocker, blocked)
  600. refute User.following?(blocked, blocker)
  601. end
  602. test "blocks tear down blocked->blocker follow relationships" do
  603. blocker = insert(:user)
  604. blocked = insert(:user)
  605. {:ok, blocked} = User.follow(blocked, blocker)
  606. refute User.following?(blocker, blocked)
  607. assert User.following?(blocked, blocker)
  608. {:ok, blocker} = User.block(blocker, blocked)
  609. blocked = User.get_cached_by_id(blocked.id)
  610. assert User.blocks?(blocker, blocked)
  611. refute User.following?(blocker, blocked)
  612. refute User.following?(blocked, blocker)
  613. end
  614. test "blocks tear down blocked->blocker subscription relationships" do
  615. blocker = insert(:user)
  616. blocked = insert(:user)
  617. {:ok, blocker} = User.subscribe(blocked, blocker)
  618. assert User.subscribed_to?(blocked, blocker)
  619. refute User.subscribed_to?(blocker, blocked)
  620. {:ok, blocker} = User.block(blocker, blocked)
  621. assert User.blocks?(blocker, blocked)
  622. refute User.subscribed_to?(blocker, blocked)
  623. refute User.subscribed_to?(blocked, blocker)
  624. end
  625. end
  626. describe "domain blocking" do
  627. test "blocks domains" do
  628. user = insert(:user)
  629. collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  630. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  631. assert User.blocks?(user, collateral_user)
  632. end
  633. test "does not block domain with same end" do
  634. user = insert(:user)
  635. collateral_user =
  636. insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
  637. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  638. refute User.blocks?(user, collateral_user)
  639. end
  640. test "does not block domain with same end if wildcard added" do
  641. user = insert(:user)
  642. collateral_user =
  643. insert(:user, %{ap_id: "https://another-awful-and-rude-instance.com/user/bully"})
  644. {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
  645. refute User.blocks?(user, collateral_user)
  646. end
  647. test "blocks domain with wildcard for subdomain" do
  648. user = insert(:user)
  649. user_from_subdomain =
  650. insert(:user, %{ap_id: "https://subdomain.awful-and-rude-instance.com/user/bully"})
  651. user_with_two_subdomains =
  652. insert(:user, %{
  653. ap_id: "https://subdomain.second_subdomain.awful-and-rude-instance.com/user/bully"
  654. })
  655. user_domain = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  656. {:ok, user} = User.block_domain(user, "*.awful-and-rude-instance.com")
  657. assert User.blocks?(user, user_from_subdomain)
  658. assert User.blocks?(user, user_with_two_subdomains)
  659. assert User.blocks?(user, user_domain)
  660. end
  661. test "unblocks domains" do
  662. user = insert(:user)
  663. collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  664. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  665. {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
  666. refute User.blocks?(user, collateral_user)
  667. end
  668. end
  669. describe "blocks_import" do
  670. test "it imports user blocks from list" do
  671. [user1, user2, user3] = insert_list(3, :user)
  672. identifiers = [
  673. user2.ap_id,
  674. user3.nickname
  675. ]
  676. {:ok, job} = User.blocks_import(user1, identifiers)
  677. result = ObanHelpers.perform(job)
  678. assert is_list(result)
  679. assert result == [user2, user3]
  680. end
  681. end
  682. test "get recipients from activity" do
  683. actor = insert(:user)
  684. user = insert(:user, local: true)
  685. user_two = insert(:user, local: false)
  686. addressed = insert(:user, local: true)
  687. addressed_remote = insert(:user, local: false)
  688. {:ok, activity} =
  689. CommonAPI.post(actor, %{
  690. "status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
  691. })
  692. assert Enum.map([actor, addressed], & &1.ap_id) --
  693. Enum.map(User.get_recipients_from_activity(activity), & &1.ap_id) == []
  694. {:ok, user} = User.follow(user, actor)
  695. {:ok, _user_two} = User.follow(user_two, actor)
  696. recipients = User.get_recipients_from_activity(activity)
  697. assert length(recipients) == 3
  698. assert user in recipients
  699. assert addressed in recipients
  700. end
  701. describe ".deactivate" do
  702. test "can de-activate then re-activate a user" do
  703. user = insert(:user)
  704. assert false == user.info.deactivated
  705. {:ok, user} = User.deactivate(user)
  706. assert true == user.info.deactivated
  707. {:ok, user} = User.deactivate(user, false)
  708. assert false == user.info.deactivated
  709. end
  710. test "hide a user from followers " do
  711. user = insert(:user)
  712. user2 = insert(:user)
  713. {:ok, user} = User.follow(user, user2)
  714. {:ok, _user} = User.deactivate(user)
  715. info = User.get_cached_user_info(user2)
  716. assert info.follower_count == 0
  717. assert [] = User.get_followers(user2)
  718. end
  719. test "hide a user from friends" do
  720. user = insert(:user)
  721. user2 = insert(:user)
  722. {:ok, user2} = User.follow(user2, user)
  723. assert User.following_count(user2) == 1
  724. {:ok, _user} = User.deactivate(user)
  725. info = User.get_cached_user_info(user2)
  726. assert info.following_count == 0
  727. assert User.following_count(user2) == 0
  728. assert [] = User.get_friends(user2)
  729. end
  730. test "hide a user's statuses from timelines and notifications" do
  731. user = insert(:user)
  732. user2 = insert(:user)
  733. {:ok, user2} = User.follow(user2, user)
  734. {:ok, activity} = CommonAPI.post(user, %{"status" => "hey @#{user2.nickname}"})
  735. activity = Repo.preload(activity, :bookmark)
  736. [notification] = Pleroma.Notification.for_user(user2)
  737. assert notification.activity.id == activity.id
  738. assert [activity] == ActivityPub.fetch_public_activities(%{}) |> Repo.preload(:bookmark)
  739. assert [%{activity | thread_muted?: CommonAPI.thread_muted?(user2, activity)}] ==
  740. ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2})
  741. {:ok, _user} = User.deactivate(user)
  742. assert [] == ActivityPub.fetch_public_activities(%{})
  743. assert [] == Pleroma.Notification.for_user(user2)
  744. assert [] ==
  745. ActivityPub.fetch_activities([user2.ap_id | user2.following], %{"user" => user2})
  746. end
  747. end
  748. describe "delete" do
  749. setup do
  750. {:ok, user} = insert(:user) |> User.set_cache()
  751. [user: user]
  752. end
  753. clear_config([:instance, :federating])
  754. test ".delete_user_activities deletes all create activities", %{user: user} do
  755. {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
  756. User.delete_user_activities(user)
  757. # TODO: Remove favorites, repeats, delete activities.
  758. refute Activity.get_by_id(activity.id)
  759. end
  760. test "it deletes deactivated user" do
  761. {:ok, user} = insert(:user, info: %{deactivated: true}) |> User.set_cache()
  762. {:ok, job} = User.delete(user)
  763. {:ok, _user} = ObanHelpers.perform(job)
  764. refute User.get_by_id(user.id)
  765. end
  766. test "it deletes a user, all follow relationships and all activities", %{user: user} do
  767. follower = insert(:user)
  768. {:ok, follower} = User.follow(follower, user)
  769. object = insert(:note, user: user)
  770. activity = insert(:note_activity, user: user, note: object)
  771. object_two = insert(:note, user: follower)
  772. activity_two = insert(:note_activity, user: follower, note: object_two)
  773. {:ok, like, _} = CommonAPI.favorite(activity_two.id, user)
  774. {:ok, like_two, _} = CommonAPI.favorite(activity.id, follower)
  775. {:ok, repeat, _} = CommonAPI.repeat(activity_two.id, user)
  776. {:ok, job} = User.delete(user)
  777. {:ok, _user} = ObanHelpers.perform(job)
  778. follower = User.get_cached_by_id(follower.id)
  779. refute User.following?(follower, user)
  780. refute User.get_by_id(user.id)
  781. assert {:ok, nil} == Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  782. user_activities =
  783. user.ap_id
  784. |> Activity.Queries.by_actor()
  785. |> Repo.all()
  786. |> Enum.map(fn act -> act.data["type"] end)
  787. assert Enum.all?(user_activities, fn act -> act in ~w(Delete Undo) end)
  788. refute Activity.get_by_id(activity.id)
  789. refute Activity.get_by_id(like.id)
  790. refute Activity.get_by_id(like_two.id)
  791. refute Activity.get_by_id(repeat.id)
  792. end
  793. test_with_mock "it sends out User Delete activity",
  794. %{user: user},
  795. Pleroma.Web.ActivityPub.Publisher,
  796. [:passthrough],
  797. [] do
  798. Pleroma.Config.put([:instance, :federating], true)
  799. {:ok, follower} = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
  800. {:ok, _} = User.follow(follower, user)
  801. {:ok, job} = User.delete(user)
  802. {:ok, _user} = ObanHelpers.perform(job)
  803. assert ObanHelpers.member?(
  804. %{
  805. "op" => "publish_one",
  806. "params" => %{
  807. "inbox" => "http://mastodon.example.org/inbox",
  808. "id" => "pleroma:fakeid"
  809. }
  810. },
  811. all_enqueued(worker: Pleroma.Workers.PublisherWorker)
  812. )
  813. end
  814. end
  815. test "get_public_key_for_ap_id fetches a user that's not in the db" do
  816. assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
  817. end
  818. describe "insert or update a user from given data" do
  819. test "with normal data" do
  820. user = insert(:user, %{nickname: "nick@name.de"})
  821. data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
  822. assert {:ok, %User{}} = User.insert_or_update_user(data)
  823. end
  824. test "with overly long fields" do
  825. current_max_length = Pleroma.Config.get([:instance, :account_field_value_length], 255)
  826. user = insert(:user, nickname: "nickname@supergood.domain")
  827. data = %{
  828. ap_id: user.ap_id,
  829. name: user.name,
  830. nickname: user.nickname,
  831. info: %{
  832. fields: [
  833. %{"name" => "myfield", "value" => String.duplicate("h", current_max_length + 1)}
  834. ]
  835. }
  836. }
  837. assert {:ok, %User{}} = User.insert_or_update_user(data)
  838. end
  839. test "with an overly long bio" do
  840. current_max_length = Pleroma.Config.get([:instance, :user_bio_length], 5000)
  841. user = insert(:user, nickname: "nickname@supergood.domain")
  842. data = %{
  843. ap_id: user.ap_id,
  844. name: user.name,
  845. nickname: user.nickname,
  846. bio: String.duplicate("h", current_max_length + 1),
  847. info: %{}
  848. }
  849. assert {:ok, %User{}} = User.insert_or_update_user(data)
  850. end
  851. test "with an overly long display name" do
  852. current_max_length = Pleroma.Config.get([:instance, :user_name_length], 100)
  853. user = insert(:user, nickname: "nickname@supergood.domain")
  854. data = %{
  855. ap_id: user.ap_id,
  856. name: String.duplicate("h", current_max_length + 1),
  857. nickname: user.nickname,
  858. info: %{}
  859. }
  860. assert {:ok, %User{}} = User.insert_or_update_user(data)
  861. end
  862. end
  863. describe "per-user rich-text filtering" do
  864. test "html_filter_policy returns default policies, when rich-text is enabled" do
  865. user = insert(:user)
  866. assert Pleroma.Config.get([:markup, :scrub_policy]) == User.html_filter_policy(user)
  867. end
  868. test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
  869. user = insert(:user, %{info: %{no_rich_text: true}})
  870. assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
  871. end
  872. end
  873. describe "caching" do
  874. test "invalidate_cache works" do
  875. user = insert(:user)
  876. _user_info = User.get_cached_user_info(user)
  877. User.invalidate_cache(user)
  878. {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  879. {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
  880. {:ok, nil} = Cachex.get(:user_cache, "user_info:#{user.id}")
  881. end
  882. test "User.delete() plugs any possible zombie objects" do
  883. user = insert(:user)
  884. {:ok, job} = User.delete(user)
  885. {:ok, _} = ObanHelpers.perform(job)
  886. {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  887. assert cached_user != user
  888. {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
  889. assert cached_user != user
  890. end
  891. end
  892. test "auth_active?/1 works correctly" do
  893. Pleroma.Config.put([:instance, :account_activation_required], true)
  894. local_user = insert(:user, local: true, info: %{confirmation_pending: true})
  895. confirmed_user = insert(:user, local: true, info: %{confirmation_pending: false})
  896. remote_user = insert(:user, local: false)
  897. refute User.auth_active?(local_user)
  898. assert User.auth_active?(confirmed_user)
  899. assert User.auth_active?(remote_user)
  900. end
  901. describe "superuser?/1" do
  902. test "returns false for unprivileged users" do
  903. user = insert(:user, local: true)
  904. refute User.superuser?(user)
  905. end
  906. test "returns false for remote users" do
  907. user = insert(:user, local: false)
  908. remote_admin_user = insert(:user, local: false, info: %{is_admin: true})
  909. refute User.superuser?(user)
  910. refute User.superuser?(remote_admin_user)
  911. end
  912. test "returns true for local moderators" do
  913. user = insert(:user, local: true, info: %{is_moderator: true})
  914. assert User.superuser?(user)
  915. end
  916. test "returns true for local admins" do
  917. user = insert(:user, local: true, info: %{is_admin: true})
  918. assert User.superuser?(user)
  919. end
  920. end
  921. describe "visible_for?/2" do
  922. test "returns true when the account is itself" do
  923. user = insert(:user, local: true)
  924. assert User.visible_for?(user, user)
  925. end
  926. test "returns false when the account is unauthenticated and auth is required" do
  927. Pleroma.Config.put([:instance, :account_activation_required], true)
  928. user = insert(:user, local: true, info: %{confirmation_pending: true})
  929. other_user = insert(:user, local: true)
  930. refute User.visible_for?(user, other_user)
  931. end
  932. test "returns true when the account is unauthenticated and auth is not required" do
  933. user = insert(:user, local: true, info: %{confirmation_pending: true})
  934. other_user = insert(:user, local: true)
  935. assert User.visible_for?(user, other_user)
  936. end
  937. test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do
  938. Pleroma.Config.put([:instance, :account_activation_required], true)
  939. user = insert(:user, local: true, info: %{confirmation_pending: true})
  940. other_user = insert(:user, local: true, info: %{is_admin: true})
  941. assert User.visible_for?(user, other_user)
  942. end
  943. end
  944. describe "parse_bio/2" do
  945. test "preserves hosts in user links text" do
  946. remote_user = insert(:user, local: false, nickname: "nick@domain.com")
  947. user = insert(:user)
  948. bio = "A.k.a. @nick@domain.com"
  949. expected_text =
  950. ~s(A.k.a. <span class="h-card"><a data-user="#{remote_user.id}" class="u-url mention" href="#{
  951. remote_user.ap_id
  952. }" rel="ugc">@<span>nick@domain.com</span></a></span>)
  953. assert expected_text == User.parse_bio(bio, user)
  954. end
  955. test "Adds rel=me on linkbacked urls" do
  956. user = insert(:user, ap_id: "https://social.example.org/users/lain")
  957. bio = "http://example.com/rel_me/null"
  958. expected_text = "<a href=\"#{bio}\">#{bio}</a>"
  959. assert expected_text == User.parse_bio(bio, user)
  960. bio = "http://example.com/rel_me/link"
  961. expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
  962. assert expected_text == User.parse_bio(bio, user)
  963. bio = "http://example.com/rel_me/anchor"
  964. expected_text = "<a href=\"#{bio}\" rel=\"me\">#{bio}</a>"
  965. assert expected_text == User.parse_bio(bio, user)
  966. end
  967. end
  968. test "follower count is updated when a follower is blocked" do
  969. user = insert(:user)
  970. follower = insert(:user)
  971. follower2 = insert(:user)
  972. follower3 = insert(:user)
  973. {:ok, follower} = User.follow(follower, user)
  974. {:ok, _follower2} = User.follow(follower2, user)
  975. {:ok, _follower3} = User.follow(follower3, user)
  976. {:ok, user} = User.block(user, follower)
  977. assert User.user_info(user).follower_count == 2
  978. end
  979. describe "list_inactive_users_query/1" do
  980. defp days_ago(days) do
  981. NaiveDateTime.add(
  982. NaiveDateTime.truncate(NaiveDateTime.utc_now(), :second),
  983. -days * 60 * 60 * 24,
  984. :second
  985. )
  986. end
  987. test "Users are inactive by default" do
  988. total = 10
  989. users =
  990. Enum.map(1..total, fn _ ->
  991. insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false})
  992. end)
  993. inactive_users_ids =
  994. Pleroma.User.list_inactive_users_query()
  995. |> Pleroma.Repo.all()
  996. |> Enum.map(& &1.id)
  997. Enum.each(users, fn user ->
  998. assert user.id in inactive_users_ids
  999. end)
  1000. end
  1001. test "Only includes users who has no recent activity" do
  1002. total = 10
  1003. users =
  1004. Enum.map(1..total, fn _ ->
  1005. insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false})
  1006. end)
  1007. {inactive, active} = Enum.split(users, trunc(total / 2))
  1008. Enum.map(active, fn user ->
  1009. to = Enum.random(users -- [user])
  1010. {:ok, _} =
  1011. CommonAPI.post(user, %{
  1012. "status" => "hey @#{to.nickname}"
  1013. })
  1014. end)
  1015. inactive_users_ids =
  1016. Pleroma.User.list_inactive_users_query()
  1017. |> Pleroma.Repo.all()
  1018. |> Enum.map(& &1.id)
  1019. Enum.each(active, fn user ->
  1020. refute user.id in inactive_users_ids
  1021. end)
  1022. Enum.each(inactive, fn user ->
  1023. assert user.id in inactive_users_ids
  1024. end)
  1025. end
  1026. test "Only includes users with no read notifications" do
  1027. total = 10
  1028. users =
  1029. Enum.map(1..total, fn _ ->
  1030. insert(:user, last_digest_emailed_at: days_ago(20), info: %{deactivated: false})
  1031. end)
  1032. [sender | recipients] = users
  1033. {inactive, active} = Enum.split(recipients, trunc(total / 2))
  1034. Enum.each(recipients, fn to ->
  1035. {:ok, _} =
  1036. CommonAPI.post(sender, %{
  1037. "status" => "hey @#{to.nickname}"
  1038. })
  1039. {:ok, _} =
  1040. CommonAPI.post(sender, %{
  1041. "status" => "hey again @#{to.nickname}"
  1042. })
  1043. end)
  1044. Enum.each(active, fn user ->
  1045. [n1, _n2] = Pleroma.Notification.for_user(user)
  1046. {:ok, _} = Pleroma.Notification.read_one(user, n1.id)
  1047. end)
  1048. inactive_users_ids =
  1049. Pleroma.User.list_inactive_users_query()
  1050. |> Pleroma.Repo.all()
  1051. |> Enum.map(& &1.id)
  1052. Enum.each(active, fn user ->
  1053. refute user.id in inactive_users_ids
  1054. end)
  1055. Enum.each(inactive, fn user ->
  1056. assert user.id in inactive_users_ids
  1057. end)
  1058. end
  1059. end
  1060. describe "toggle_confirmation/1" do
  1061. test "if user is confirmed" do
  1062. user = insert(:user, info: %{confirmation_pending: false})
  1063. {:ok, user} = User.toggle_confirmation(user)
  1064. assert user.info.confirmation_pending
  1065. assert user.info.confirmation_token
  1066. end
  1067. test "if user is unconfirmed" do
  1068. user = insert(:user, info: %{confirmation_pending: true, confirmation_token: "some token"})
  1069. {:ok, user} = User.toggle_confirmation(user)
  1070. refute user.info.confirmation_pending
  1071. refute user.info.confirmation_token
  1072. end
  1073. end
  1074. describe "ensure_keys_present" do
  1075. test "it creates keys for a user and stores them in info" do
  1076. user = insert(:user)
  1077. refute is_binary(user.info.keys)
  1078. {:ok, user} = User.ensure_keys_present(user)
  1079. assert is_binary(user.info.keys)
  1080. end
  1081. test "it doesn't create keys if there already are some" do
  1082. user = insert(:user, %{info: %{keys: "xxx"}})
  1083. {:ok, user} = User.ensure_keys_present(user)
  1084. assert user.info.keys == "xxx"
  1085. end
  1086. end
  1087. describe "get_ap_ids_by_nicknames" do
  1088. test "it returns a list of AP ids for a given set of nicknames" do
  1089. user = insert(:user)
  1090. user_two = insert(:user)
  1091. ap_ids = User.get_ap_ids_by_nicknames([user.nickname, user_two.nickname, "nonexistent"])
  1092. assert length(ap_ids) == 2
  1093. assert user.ap_id in ap_ids
  1094. assert user_two.ap_id in ap_ids
  1095. end
  1096. end
  1097. describe "sync followers count" do
  1098. setup do
  1099. user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed")
  1100. user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2")
  1101. insert(:user, local: true)
  1102. insert(:user, local: false, info: %{deactivated: true})
  1103. {:ok, user1: user1, user2: user2}
  1104. end
  1105. test "external_users/1 external active users with limit", %{user1: user1, user2: user2} do
  1106. [fdb_user1] = User.external_users(limit: 1)
  1107. assert fdb_user1.ap_id
  1108. assert fdb_user1.ap_id == user1.ap_id
  1109. assert fdb_user1.id == user1.id
  1110. [fdb_user2] = User.external_users(max_id: fdb_user1.id, limit: 1)
  1111. assert fdb_user2.ap_id
  1112. assert fdb_user2.ap_id == user2.ap_id
  1113. assert fdb_user2.id == user2.id
  1114. assert User.external_users(max_id: fdb_user2.id, limit: 1) == []
  1115. end
  1116. end
  1117. describe "set_info_cache/2" do
  1118. setup do
  1119. user = insert(:user)
  1120. {:ok, user: user}
  1121. end
  1122. test "update from args", %{user: user} do
  1123. User.set_info_cache(user, %{following_count: 15, follower_count: 18})
  1124. %{follower_count: followers, following_count: following} = User.get_cached_user_info(user)
  1125. assert followers == 18
  1126. assert following == 15
  1127. end
  1128. test "without args", %{user: user} do
  1129. User.set_info_cache(user, %{})
  1130. %{follower_count: followers, following_count: following} = User.get_cached_user_info(user)
  1131. assert followers == 0
  1132. assert following == 0
  1133. end
  1134. end
  1135. describe "user_info/2" do
  1136. setup do
  1137. user = insert(:user)
  1138. {:ok, user: user}
  1139. end
  1140. test "update from args", %{user: user} do
  1141. %{follower_count: followers, following_count: following} =
  1142. User.user_info(user, %{following_count: 15, follower_count: 18})
  1143. assert followers == 18
  1144. assert following == 15
  1145. end
  1146. test "without args", %{user: user} do
  1147. %{follower_count: followers, following_count: following} = User.user_info(user)
  1148. assert followers == 0
  1149. assert following == 0
  1150. end
  1151. end
  1152. describe "is_internal_user?/1" do
  1153. test "non-internal user returns false" do
  1154. user = insert(:user)
  1155. refute User.is_internal_user?(user)
  1156. end
  1157. test "user with no nickname returns true" do
  1158. user = insert(:user, %{nickname: nil})
  1159. assert User.is_internal_user?(user)
  1160. end
  1161. test "user with internal-prefixed nickname returns true" do
  1162. user = insert(:user, %{nickname: "internal.test"})
  1163. assert User.is_internal_user?(user)
  1164. end
  1165. end
  1166. describe "update_and_set_cache/1" do
  1167. test "returns error when user is stale instead Ecto.StaleEntryError" do
  1168. user = insert(:user)
  1169. changeset = Ecto.Changeset.change(user, bio: "test")
  1170. Repo.delete(user)
  1171. assert {:error, %Ecto.Changeset{errors: [id: {"is stale", [stale: true]}], valid?: false}} =
  1172. User.update_and_set_cache(changeset)
  1173. end
  1174. test "performs update cache if user updated" do
  1175. user = insert(:user)
  1176. assert {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1177. changeset = Ecto.Changeset.change(user, bio: "test-bio")
  1178. assert {:ok, %User{bio: "test-bio"} = user} = User.update_and_set_cache(changeset)
  1179. assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1180. assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id)
  1181. end
  1182. end
  1183. describe "following/followers synchronization" do
  1184. clear_config([:instance, :external_user_synchronization])
  1185. test "updates the counters normally on following/getting a follow when disabled" do
  1186. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1187. user = insert(:user)
  1188. other_user =
  1189. insert(:user,
  1190. local: false,
  1191. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1192. following_address: "http://localhost:4001/users/masto_closed/following",
  1193. info: %{ap_enabled: true}
  1194. )
  1195. assert User.user_info(other_user).following_count == 0
  1196. assert User.user_info(other_user).follower_count == 0
  1197. {:ok, user} = Pleroma.User.follow(user, other_user)
  1198. other_user = Pleroma.User.get_by_id(other_user.id)
  1199. assert User.user_info(user).following_count == 1
  1200. assert User.user_info(other_user).follower_count == 1
  1201. end
  1202. test "syncronizes the counters with the remote instance for the followed when enabled" do
  1203. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1204. user = insert(:user)
  1205. other_user =
  1206. insert(:user,
  1207. local: false,
  1208. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1209. following_address: "http://localhost:4001/users/masto_closed/following",
  1210. info: %{ap_enabled: true}
  1211. )
  1212. assert User.user_info(other_user).following_count == 0
  1213. assert User.user_info(other_user).follower_count == 0
  1214. Pleroma.Config.put([:instance, :external_user_synchronization], true)
  1215. {:ok, _user} = User.follow(user, other_user)
  1216. other_user = User.get_by_id(other_user.id)
  1217. assert User.user_info(other_user).follower_count == 437
  1218. end
  1219. test "syncronizes the counters with the remote instance for the follower when enabled" do
  1220. Pleroma.Config.put([:instance, :external_user_synchronization], false)
  1221. user = insert(:user)
  1222. other_user =
  1223. insert(:user,
  1224. local: false,
  1225. follower_address: "http://localhost:4001/users/masto_closed/followers",
  1226. following_address: "http://localhost:4001/users/masto_closed/following",
  1227. info: %{ap_enabled: true}
  1228. )
  1229. assert User.user_info(other_user).following_count == 0
  1230. assert User.user_info(other_user).follower_count == 0
  1231. Pleroma.Config.put([:instance, :external_user_synchronization], true)
  1232. {:ok, other_user} = User.follow(other_user, user)
  1233. assert User.user_info(other_user).following_count == 152
  1234. end
  1235. end
  1236. describe "change_email/2" do
  1237. setup do
  1238. [user: insert(:user)]
  1239. end
  1240. test "blank email returns error", %{user: user} do
  1241. assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, "")
  1242. assert {:error, %{errors: [email: {"can't be blank", _}]}} = User.change_email(user, nil)
  1243. end
  1244. test "non unique email returns error", %{user: user} do
  1245. %{email: email} = insert(:user)
  1246. assert {:error, %{errors: [email: {"has already been taken", _}]}} =
  1247. User.change_email(user, email)
  1248. end
  1249. test "invalid email returns error", %{user: user} do
  1250. assert {:error, %{errors: [email: {"has invalid format", _}]}} =
  1251. User.change_email(user, "cofe")
  1252. end
  1253. test "changes email", %{user: user} do
  1254. assert {:ok, %User{email: "cofe@cofe.party"}} = User.change_email(user, "cofe@cofe.party")
  1255. end
  1256. end
  1257. describe "set_password_reset_pending/2" do
  1258. setup do
  1259. [user: insert(:user)]
  1260. end
  1261. test "sets password_reset_pending to true", %{user: user} do
  1262. %{password_reset_pending: password_reset_pending} = user.info
  1263. refute password_reset_pending
  1264. {:ok, %{info: %{password_reset_pending: password_reset_pending}}} =
  1265. User.force_password_reset(user)
  1266. assert password_reset_pending
  1267. end
  1268. end
  1269. test "change_info/2" do
  1270. user = insert(:user)
  1271. assert user.info.hide_follows == false
  1272. changeset = User.change_info(user, &User.Info.profile_update(&1, %{hide_follows: true}))
  1273. assert changeset.changes.info.changes.hide_follows == true
  1274. end
  1275. test "update_info/2" do
  1276. user = insert(:user)
  1277. assert user.info.hide_follows == false
  1278. assert {:ok, _} = User.update_info(user, &User.Info.profile_update(&1, %{hide_follows: true}))
  1279. assert %{info: %{hide_follows: true}} = Repo.get(User, user.id)
  1280. assert {:ok, %{info: %{hide_follows: true}}} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  1281. end
  1282. end