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.

636 lines
18KB

  1. defmodule Pleroma.UserTest do
  2. alias Pleroma.Builders.UserBuilder
  3. alias Pleroma.{User, Repo, Activity}
  4. alias Pleroma.Web.CommonAPI
  5. use Pleroma.DataCase
  6. import Pleroma.Factory
  7. setup_all do
  8. Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
  9. :ok
  10. end
  11. test "ap_id returns the activity pub id for the user" do
  12. user = UserBuilder.build()
  13. expected_ap_id = "#{Pleroma.Web.base_url()}/users/#{user.nickname}"
  14. assert expected_ap_id == User.ap_id(user)
  15. end
  16. test "ap_followers returns the followers collection for the user" do
  17. user = UserBuilder.build()
  18. expected_followers_collection = "#{User.ap_id(user)}/followers"
  19. assert expected_followers_collection == User.ap_followers(user)
  20. end
  21. test "follow takes a user and another user" do
  22. user = insert(:user)
  23. followed = insert(:user)
  24. {:ok, user} = User.follow(user, followed)
  25. user = Repo.get(User, user.id)
  26. followed = User.get_by_ap_id(followed.ap_id)
  27. assert followed.info.follower_count == 1
  28. assert User.ap_followers(followed) in user.following
  29. end
  30. test "can't follow a deactivated users" do
  31. user = insert(:user)
  32. followed = insert(:user, info: %{deactivated: true})
  33. {:error, _} = User.follow(user, followed)
  34. end
  35. test "can't follow a user who blocked us" do
  36. blocker = insert(:user)
  37. blockee = insert(:user)
  38. {:ok, blocker} = User.block(blocker, blockee)
  39. {:error, _} = User.follow(blockee, blocker)
  40. end
  41. test "local users do not automatically follow local locked accounts" do
  42. follower = insert(:user, info: %{locked: true})
  43. followed = insert(:user, info: %{locked: true})
  44. {:ok, follower} = User.maybe_direct_follow(follower, followed)
  45. refute User.following?(follower, followed)
  46. end
  47. # This is a somewhat useless test.
  48. # test "following a remote user will ensure a websub subscription is present" do
  49. # user = insert(:user)
  50. # {:ok, followed} = OStatus.make_user("shp@social.heldscal.la")
  51. # assert followed.local == false
  52. # {:ok, user} = User.follow(user, followed)
  53. # assert User.ap_followers(followed) in user.following
  54. # query = from w in WebsubClientSubscription,
  55. # where: w.topic == ^followed.info["topic"]
  56. # websub = Repo.one(query)
  57. # assert websub
  58. # end
  59. test "unfollow takes a user and another user" do
  60. followed = insert(:user)
  61. user = insert(:user, %{following: [User.ap_followers(followed)]})
  62. {:ok, user, _activity} = User.unfollow(user, followed)
  63. user = Repo.get(User, user.id)
  64. assert user.following == []
  65. end
  66. test "unfollow doesn't unfollow yourself" do
  67. user = insert(:user)
  68. {:error, _} = User.unfollow(user, user)
  69. user = Repo.get(User, user.id)
  70. assert user.following == [user.ap_id]
  71. end
  72. test "test if a user is following another user" do
  73. followed = insert(:user)
  74. user = insert(:user, %{following: [User.ap_followers(followed)]})
  75. assert User.following?(user, followed)
  76. refute User.following?(followed, user)
  77. end
  78. describe "user registration" do
  79. @full_user_data %{
  80. bio: "A guy",
  81. name: "my name",
  82. nickname: "nick",
  83. password: "test",
  84. password_confirmation: "test",
  85. email: "email@example.com"
  86. }
  87. test "it requires an email, name, nickname and password, bio is optional" do
  88. @full_user_data
  89. |> Map.keys()
  90. |> Enum.each(fn key ->
  91. params = Map.delete(@full_user_data, key)
  92. changeset = User.register_changeset(%User{}, params)
  93. assert if key == :bio, do: changeset.valid?, else: not changeset.valid?
  94. end)
  95. end
  96. test "it sets the password_hash, ap_id and following fields" do
  97. changeset = User.register_changeset(%User{}, @full_user_data)
  98. assert changeset.valid?
  99. assert is_binary(changeset.changes[:password_hash])
  100. assert changeset.changes[:ap_id] == User.ap_id(%User{nickname: @full_user_data.nickname})
  101. assert changeset.changes[:following] == [
  102. User.ap_followers(%User{nickname: @full_user_data.nickname})
  103. ]
  104. assert changeset.changes.follower_address == "#{changeset.changes.ap_id}/followers"
  105. end
  106. test "it ensures info is not nil" do
  107. changeset = User.register_changeset(%User{}, @full_user_data)
  108. assert changeset.valid?
  109. {:ok, user} =
  110. changeset
  111. |> Repo.insert()
  112. refute is_nil(user.info)
  113. end
  114. end
  115. describe "get_or_fetch/1" do
  116. test "gets an existing user by nickname" do
  117. user = insert(:user)
  118. fetched_user = User.get_or_fetch(user.nickname)
  119. assert user == fetched_user
  120. end
  121. test "gets an existing user by ap_id" do
  122. ap_id = "http://mastodon.example.org/users/admin"
  123. user =
  124. insert(
  125. :user,
  126. local: false,
  127. nickname: "admin@mastodon.example.org",
  128. ap_id: ap_id,
  129. info: %{}
  130. )
  131. fetched_user = User.get_or_fetch(ap_id)
  132. freshed_user = refresh_record(user)
  133. assert freshed_user == fetched_user
  134. end
  135. end
  136. describe "fetching a user from nickname or trying to build one" do
  137. test "gets an existing user" do
  138. user = insert(:user)
  139. fetched_user = User.get_or_fetch_by_nickname(user.nickname)
  140. assert user == fetched_user
  141. end
  142. test "gets an existing user, case insensitive" do
  143. user = insert(:user, nickname: "nick")
  144. fetched_user = User.get_or_fetch_by_nickname("NICK")
  145. assert user == fetched_user
  146. end
  147. test "fetches an external user via ostatus if no user exists" do
  148. fetched_user = User.get_or_fetch_by_nickname("shp@social.heldscal.la")
  149. assert fetched_user.nickname == "shp@social.heldscal.la"
  150. end
  151. test "returns nil if no user could be fetched" do
  152. fetched_user = User.get_or_fetch_by_nickname("nonexistant@social.heldscal.la")
  153. assert fetched_user == nil
  154. end
  155. test "returns nil for nonexistant local user" do
  156. fetched_user = User.get_or_fetch_by_nickname("nonexistant")
  157. assert fetched_user == nil
  158. end
  159. test "updates an existing user, if stale" do
  160. a_week_ago = NaiveDateTime.add(NaiveDateTime.utc_now(), -604_800)
  161. orig_user =
  162. insert(
  163. :user,
  164. local: false,
  165. nickname: "admin@mastodon.example.org",
  166. ap_id: "http://mastodon.example.org/users/admin",
  167. last_refreshed_at: a_week_ago,
  168. info: %{}
  169. )
  170. assert orig_user.last_refreshed_at == a_week_ago
  171. user = User.get_or_fetch_by_ap_id("http://mastodon.example.org/users/admin")
  172. assert user.info.source_data["endpoints"]
  173. refute user.last_refreshed_at == orig_user.last_refreshed_at
  174. end
  175. end
  176. test "returns an ap_id for a user" do
  177. user = insert(:user)
  178. assert User.ap_id(user) ==
  179. Pleroma.Web.Router.Helpers.o_status_url(
  180. Pleroma.Web.Endpoint,
  181. :feed_redirect,
  182. user.nickname
  183. )
  184. end
  185. test "returns an ap_followers link for a user" do
  186. user = insert(:user)
  187. assert User.ap_followers(user) ==
  188. Pleroma.Web.Router.Helpers.o_status_url(
  189. Pleroma.Web.Endpoint,
  190. :feed_redirect,
  191. user.nickname
  192. ) <> "/followers"
  193. end
  194. describe "remote user creation changeset" do
  195. @valid_remote %{
  196. bio: "hello",
  197. name: "Someone",
  198. nickname: "a@b.de",
  199. ap_id: "http...",
  200. info: %{some: "info"},
  201. avatar: %{some: "avatar"}
  202. }
  203. test "it confirms validity" do
  204. cs = User.remote_user_creation(@valid_remote)
  205. assert cs.valid?
  206. end
  207. test "it sets the follower_adress" do
  208. cs = User.remote_user_creation(@valid_remote)
  209. # remote users get a fake local follower address
  210. assert cs.changes.follower_address ==
  211. User.ap_followers(%User{nickname: @valid_remote[:nickname]})
  212. end
  213. test "it enforces the fqn format for nicknames" do
  214. cs = User.remote_user_creation(%{@valid_remote | nickname: "bla"})
  215. assert cs.changes.local == false
  216. assert cs.changes.avatar
  217. refute cs.valid?
  218. end
  219. test "it has required fields" do
  220. [:name, :ap_id]
  221. |> Enum.each(fn field ->
  222. cs = User.remote_user_creation(Map.delete(@valid_remote, field))
  223. refute cs.valid?
  224. end)
  225. end
  226. test "it restricts some sizes" do
  227. [bio: 5000, name: 100]
  228. |> Enum.each(fn {field, size} ->
  229. string = String.pad_leading(".", size)
  230. cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
  231. assert cs.valid?
  232. string = String.pad_leading(".", size + 1)
  233. cs = User.remote_user_creation(Map.put(@valid_remote, field, string))
  234. refute cs.valid?
  235. end)
  236. end
  237. end
  238. describe "followers and friends" do
  239. test "gets all followers for a given user" do
  240. user = insert(:user)
  241. follower_one = insert(:user)
  242. follower_two = insert(:user)
  243. not_follower = insert(:user)
  244. {:ok, follower_one} = User.follow(follower_one, user)
  245. {:ok, follower_two} = User.follow(follower_two, user)
  246. {:ok, res} = User.get_followers(user)
  247. assert Enum.member?(res, follower_one)
  248. assert Enum.member?(res, follower_two)
  249. refute Enum.member?(res, not_follower)
  250. end
  251. test "gets all friends (followed users) for a given user" do
  252. user = insert(:user)
  253. followed_one = insert(:user)
  254. followed_two = insert(:user)
  255. not_followed = insert(:user)
  256. {:ok, user} = User.follow(user, followed_one)
  257. {:ok, user} = User.follow(user, followed_two)
  258. {:ok, res} = User.get_friends(user)
  259. followed_one = User.get_by_ap_id(followed_one.ap_id)
  260. followed_two = User.get_by_ap_id(followed_two.ap_id)
  261. assert Enum.member?(res, followed_one)
  262. assert Enum.member?(res, followed_two)
  263. refute Enum.member?(res, not_followed)
  264. end
  265. end
  266. describe "updating note and follower count" do
  267. test "it sets the info->note_count property" do
  268. note = insert(:note)
  269. user = User.get_by_ap_id(note.data["actor"])
  270. assert user.info.note_count == 0
  271. {:ok, user} = User.update_note_count(user)
  272. assert user.info.note_count == 1
  273. end
  274. test "it increases the info->note_count property" do
  275. note = insert(:note)
  276. user = User.get_by_ap_id(note.data["actor"])
  277. assert user.info.note_count == 0
  278. {:ok, user} = User.increase_note_count(user)
  279. assert user.info.note_count == 1
  280. {:ok, user} = User.increase_note_count(user)
  281. assert user.info.note_count == 2
  282. end
  283. test "it decreases the info->note_count property" do
  284. note = insert(:note)
  285. user = User.get_by_ap_id(note.data["actor"])
  286. assert user.info.note_count == 0
  287. {:ok, user} = User.increase_note_count(user)
  288. assert user.info.note_count == 1
  289. {:ok, user} = User.decrease_note_count(user)
  290. assert user.info.note_count == 0
  291. {:ok, user} = User.decrease_note_count(user)
  292. assert user.info.note_count == 0
  293. end
  294. test "it sets the info->follower_count property" do
  295. user = insert(:user)
  296. follower = insert(:user)
  297. User.follow(follower, user)
  298. assert user.info.follower_count == 0
  299. {:ok, user} = User.update_follower_count(user)
  300. assert user.info.follower_count == 1
  301. end
  302. end
  303. describe "blocks" do
  304. test "it blocks people" do
  305. user = insert(:user)
  306. blocked_user = insert(:user)
  307. refute User.blocks?(user, blocked_user)
  308. {:ok, user} = User.block(user, blocked_user)
  309. assert User.blocks?(user, blocked_user)
  310. end
  311. test "it unblocks users" do
  312. user = insert(:user)
  313. blocked_user = insert(:user)
  314. {:ok, user} = User.block(user, blocked_user)
  315. {:ok, user} = User.unblock(user, blocked_user)
  316. refute User.blocks?(user, blocked_user)
  317. end
  318. test "blocks tear down cyclical follow relationships" do
  319. blocker = insert(:user)
  320. blocked = insert(:user)
  321. {:ok, blocker} = User.follow(blocker, blocked)
  322. {:ok, blocked} = User.follow(blocked, blocker)
  323. assert User.following?(blocker, blocked)
  324. assert User.following?(blocked, blocker)
  325. {:ok, blocker} = User.block(blocker, blocked)
  326. blocked = Repo.get(User, blocked.id)
  327. assert User.blocks?(blocker, blocked)
  328. refute User.following?(blocker, blocked)
  329. refute User.following?(blocked, blocker)
  330. end
  331. test "blocks tear down blocker->blocked follow relationships" do
  332. blocker = insert(:user)
  333. blocked = insert(:user)
  334. {:ok, blocker} = User.follow(blocker, blocked)
  335. assert User.following?(blocker, blocked)
  336. refute User.following?(blocked, blocker)
  337. {:ok, blocker} = User.block(blocker, blocked)
  338. blocked = Repo.get(User, blocked.id)
  339. assert User.blocks?(blocker, blocked)
  340. refute User.following?(blocker, blocked)
  341. refute User.following?(blocked, blocker)
  342. end
  343. test "blocks tear down blocked->blocker follow relationships" do
  344. blocker = insert(:user)
  345. blocked = insert(:user)
  346. {:ok, blocked} = User.follow(blocked, blocker)
  347. refute User.following?(blocker, blocked)
  348. assert User.following?(blocked, blocker)
  349. {:ok, blocker} = User.block(blocker, blocked)
  350. blocked = Repo.get(User, blocked.id)
  351. assert User.blocks?(blocker, blocked)
  352. refute User.following?(blocker, blocked)
  353. refute User.following?(blocked, blocker)
  354. end
  355. end
  356. describe "domain blocking" do
  357. test "blocks domains" do
  358. user = insert(:user)
  359. collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  360. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  361. assert User.blocks?(user, collateral_user)
  362. end
  363. test "unblocks domains" do
  364. user = insert(:user)
  365. collateral_user = insert(:user, %{ap_id: "https://awful-and-rude-instance.com/user/bully"})
  366. {:ok, user} = User.block_domain(user, "awful-and-rude-instance.com")
  367. {:ok, user} = User.unblock_domain(user, "awful-and-rude-instance.com")
  368. refute User.blocks?(user, collateral_user)
  369. end
  370. end
  371. test "get recipients from activity" do
  372. actor = insert(:user)
  373. user = insert(:user, local: true)
  374. user_two = insert(:user, local: false)
  375. addressed = insert(:user, local: true)
  376. addressed_remote = insert(:user, local: false)
  377. {:ok, activity} =
  378. CommonAPI.post(actor, %{
  379. "status" => "hey @#{addressed.nickname} @#{addressed_remote.nickname}"
  380. })
  381. assert [addressed] == User.get_recipients_from_activity(activity)
  382. {:ok, user} = User.follow(user, actor)
  383. {:ok, _user_two} = User.follow(user_two, actor)
  384. recipients = User.get_recipients_from_activity(activity)
  385. assert length(recipients) == 2
  386. assert user in recipients
  387. assert addressed in recipients
  388. end
  389. test ".deactivate can de-activate then re-activate a user" do
  390. user = insert(:user)
  391. assert false == user.info.deactivated
  392. {:ok, user} = User.deactivate(user)
  393. assert true == user.info.deactivated
  394. {:ok, user} = User.deactivate(user, false)
  395. assert false == user.info.deactivated
  396. end
  397. test ".delete deactivates a user, all follow relationships and all create activities" do
  398. user = insert(:user)
  399. followed = insert(:user)
  400. follower = insert(:user)
  401. {:ok, user} = User.follow(user, followed)
  402. {:ok, follower} = User.follow(follower, user)
  403. {:ok, activity} = CommonAPI.post(user, %{"status" => "2hu"})
  404. {:ok, activity_two} = CommonAPI.post(follower, %{"status" => "3hu"})
  405. {:ok, _, _} = CommonAPI.favorite(activity_two.id, user)
  406. {:ok, _, _} = CommonAPI.favorite(activity.id, follower)
  407. {:ok, _, _} = CommonAPI.repeat(activity.id, follower)
  408. {:ok, _} = User.delete(user)
  409. followed = Repo.get(User, followed.id)
  410. follower = Repo.get(User, follower.id)
  411. user = Repo.get(User, user.id)
  412. assert user.info.deactivated
  413. refute User.following?(user, followed)
  414. refute User.following?(followed, follower)
  415. # TODO: Remove favorites, repeats, delete activities.
  416. refute Repo.get(Activity, activity.id)
  417. end
  418. test "get_public_key_for_ap_id fetches a user that's not in the db" do
  419. assert {:ok, _key} = User.get_public_key_for_ap_id("http://mastodon.example.org/users/admin")
  420. end
  421. test "insert or update a user from given data" do
  422. user = insert(:user, %{nickname: "nick@name.de"})
  423. data = %{ap_id: user.ap_id <> "xxx", name: user.name, nickname: user.nickname}
  424. assert {:ok, %User{}} = User.insert_or_update_user(data)
  425. end
  426. describe "per-user rich-text filtering" do
  427. test "html_filter_policy returns nil when rich-text is enabled" do
  428. user = insert(:user)
  429. assert nil == User.html_filter_policy(user)
  430. end
  431. test "html_filter_policy returns TwitterText scrubber when rich-text is disabled" do
  432. user = insert(:user, %{info: %{no_rich_text: true}})
  433. assert Pleroma.HTML.Scrubber.TwitterText == User.html_filter_policy(user)
  434. end
  435. end
  436. describe "caching" do
  437. test "invalidate_cache works" do
  438. user = insert(:user)
  439. _user_info = User.get_cached_user_info(user)
  440. User.invalidate_cache(user)
  441. {:ok, nil} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  442. {:ok, nil} = Cachex.get(:user_cache, "nickname:#{user.nickname}")
  443. {:ok, nil} = Cachex.get(:user_cache, "user_info:#{user.id}")
  444. end
  445. test "User.delete() plugs any possible zombie objects" do
  446. user = insert(:user)
  447. {:ok, _} = User.delete(user)
  448. {:ok, cached_user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}")
  449. assert cached_user != user
  450. {:ok, cached_user} = Cachex.get(:user_cache, "nickname:#{user.ap_id}")
  451. assert cached_user != user
  452. end
  453. end
  454. describe "User.search" do
  455. test "finds a user, ranking by similarity" do
  456. _user = insert(:user, %{name: "lain"})
  457. _user_two = insert(:user, %{name: "ean"})
  458. _user_three = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social"})
  459. user_four = insert(:user, %{nickname: "lain@pleroma.soykaf.com"})
  460. assert user_four ==
  461. User.search("lain@ple") |> List.first() |> Map.put(:search_distance, nil)
  462. end
  463. end
  464. end