Local copy of Pleroma, an ActivityPub server software. Contains modifications running live on fedi.underscore.world
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.

user_test.exs 47KB

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