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.

279 lines
9.1KB

  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.UserSearchTest do
  5. alias Pleroma.Repo
  6. alias Pleroma.User
  7. use Pleroma.DataCase
  8. import Pleroma.Factory
  9. setup_all do
  10. Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
  11. :ok
  12. end
  13. describe "User.search" do
  14. test "accepts limit parameter" do
  15. Enum.each(0..4, &insert(:user, %{nickname: "john#{&1}"}))
  16. assert length(User.search("john", limit: 3)) == 3
  17. assert length(User.search("john")) == 5
  18. end
  19. test "accepts offset parameter" do
  20. Enum.each(0..4, &insert(:user, %{nickname: "john#{&1}"}))
  21. assert length(User.search("john", limit: 3)) == 3
  22. assert length(User.search("john", limit: 3, offset: 3)) == 2
  23. end
  24. test "finds a user by full or partial nickname" do
  25. user = insert(:user, %{nickname: "john"})
  26. Enum.each(["john", "jo", "j"], fn query ->
  27. assert user ==
  28. User.search(query)
  29. |> List.first()
  30. |> Map.put(:search_rank, nil)
  31. |> Map.put(:search_type, nil)
  32. end)
  33. end
  34. test "finds a user by full or partial name" do
  35. user = insert(:user, %{name: "John Doe"})
  36. Enum.each(["John Doe", "JOHN", "doe", "j d", "j", "d"], fn query ->
  37. assert user ==
  38. User.search(query)
  39. |> List.first()
  40. |> Map.put(:search_rank, nil)
  41. |> Map.put(:search_type, nil)
  42. end)
  43. end
  44. test "finds users, considering density of matched tokens" do
  45. u1 = insert(:user, %{name: "Bar Bar plus Word Word"})
  46. u2 = insert(:user, %{name: "Word Word Bar Bar Bar"})
  47. assert [u2.id, u1.id] == Enum.map(User.search("bar word"), & &1.id)
  48. end
  49. test "finds users, boosting ranks of friends and followers" do
  50. u1 = insert(:user)
  51. u2 = insert(:user, %{name: "Doe"})
  52. follower = insert(:user, %{name: "Doe"})
  53. friend = insert(:user, %{name: "Doe"})
  54. {:ok, follower} = User.follow(follower, u1)
  55. {:ok, u1} = User.follow(u1, friend)
  56. assert [friend.id, follower.id, u2.id] --
  57. Enum.map(User.search("doe", resolve: false, for_user: u1), & &1.id) == []
  58. end
  59. test "finds followers of user by partial name" do
  60. u1 = insert(:user)
  61. u2 = insert(:user, %{name: "Jimi"})
  62. follower_jimi = insert(:user, %{name: "Jimi Hendrix"})
  63. follower_lizz = insert(:user, %{name: "Lizz Wright"})
  64. friend = insert(:user, %{name: "Jimi"})
  65. {:ok, follower_jimi} = User.follow(follower_jimi, u1)
  66. {:ok, _follower_lizz} = User.follow(follower_lizz, u2)
  67. {:ok, u1} = User.follow(u1, friend)
  68. assert Enum.map(User.search("jimi", following: true, for_user: u1), & &1.id) == [
  69. follower_jimi.id
  70. ]
  71. assert User.search("lizz", following: true, for_user: u1) == []
  72. end
  73. test "find local and remote users for authenticated users" do
  74. u1 = insert(:user, %{name: "lain"})
  75. u2 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
  76. u3 = insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
  77. results =
  78. "lain"
  79. |> User.search(for_user: u1)
  80. |> Enum.map(& &1.id)
  81. |> Enum.sort()
  82. assert [u1.id, u2.id, u3.id] == results
  83. end
  84. test "find only local users for unauthenticated users" do
  85. %{id: id} = insert(:user, %{name: "lain"})
  86. insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
  87. insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
  88. assert [%{id: ^id}] = User.search("lain")
  89. end
  90. test "find only local users for authenticated users when `limit_to_local_content` is `:all`" do
  91. Pleroma.Config.put([:instance, :limit_to_local_content], :all)
  92. %{id: id} = insert(:user, %{name: "lain"})
  93. insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
  94. insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
  95. assert [%{id: ^id}] = User.search("lain")
  96. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  97. end
  98. test "find all users for unauthenticated users when `limit_to_local_content` is `false`" do
  99. Pleroma.Config.put([:instance, :limit_to_local_content], false)
  100. u1 = insert(:user, %{name: "lain"})
  101. u2 = insert(:user, %{name: "ebn", nickname: "lain@mastodon.social", local: false})
  102. u3 = insert(:user, %{nickname: "lain@pleroma.soykaf.com", local: false})
  103. results =
  104. "lain"
  105. |> User.search()
  106. |> Enum.map(& &1.id)
  107. |> Enum.sort()
  108. assert [u1.id, u2.id, u3.id] == results
  109. Pleroma.Config.put([:instance, :limit_to_local_content], :unauthenticated)
  110. end
  111. test "does not yield false-positive matches" do
  112. insert(:user, %{name: "John Doe"})
  113. Enum.each(["mary", "a", ""], fn query ->
  114. assert [] == User.search(query)
  115. end)
  116. end
  117. test "works with URIs" do
  118. user = insert(:user)
  119. results =
  120. User.search("http://mastodon.example.org/users/admin", resolve: true, for_user: user)
  121. result = results |> List.first()
  122. user = User.get_cached_by_ap_id("http://mastodon.example.org/users/admin")
  123. assert length(results) == 1
  124. expected =
  125. result
  126. |> Map.put(:search_rank, nil)
  127. |> Map.put(:search_type, nil)
  128. |> Map.put(:last_digest_emailed_at, nil)
  129. assert user == expected
  130. end
  131. test "excludes a blocked users from search result" do
  132. user = insert(:user, %{nickname: "Bill"})
  133. [blocked_user | users] = Enum.map(0..3, &insert(:user, %{nickname: "john#{&1}"}))
  134. blocked_user2 =
  135. insert(
  136. :user,
  137. %{nickname: "john awful", ap_id: "https://awful-and-rude-instance.com/user/bully"}
  138. )
  139. User.block_domain(user, "awful-and-rude-instance.com")
  140. User.block(user, blocked_user)
  141. account_ids = User.search("john", for_user: refresh_record(user)) |> collect_ids
  142. assert account_ids == collect_ids(users)
  143. refute Enum.member?(account_ids, blocked_user.id)
  144. refute Enum.member?(account_ids, blocked_user2.id)
  145. assert length(account_ids) == 3
  146. end
  147. test "local user has the same search_rank as for users with the same nickname, but another domain" do
  148. user = insert(:user)
  149. insert(:user, nickname: "lain@mastodon.social")
  150. insert(:user, nickname: "lain")
  151. insert(:user, nickname: "lain@pleroma.social")
  152. assert User.search("lain@localhost", resolve: true, for_user: user)
  153. |> Enum.each(fn u -> u.search_rank == 0.5 end)
  154. end
  155. test "localhost is the part of the domain" do
  156. user = insert(:user)
  157. insert(:user, nickname: "another@somedomain")
  158. insert(:user, nickname: "lain")
  159. insert(:user, nickname: "lain@examplelocalhost")
  160. result = User.search("lain@examplelocalhost", resolve: true, for_user: user)
  161. assert Enum.each(result, fn u -> u.search_rank == 0.5 end)
  162. assert length(result) == 2
  163. end
  164. test "local user search with users" do
  165. user = insert(:user)
  166. local_user = insert(:user, nickname: "lain")
  167. insert(:user, nickname: "another@localhost.com")
  168. insert(:user, nickname: "localhost@localhost.com")
  169. [result] = User.search("lain@localhost", resolve: true, for_user: user)
  170. assert Map.put(result, :search_rank, nil) |> Map.put(:search_type, nil) == local_user
  171. end
  172. test "works with idna domains" do
  173. user = insert(:user, nickname: "lain@" <> to_string(:idna.encode("zetsubou.みんな")))
  174. results = User.search("lain@zetsubou.みんな", resolve: false, for_user: user)
  175. result = List.first(results)
  176. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  177. end
  178. test "works with idna domains converted input" do
  179. user = insert(:user, nickname: "lain@" <> to_string(:idna.encode("zetsubou.みんな")))
  180. results =
  181. User.search("lain@zetsubou." <> to_string(:idna.encode("zetsubou.みんな")),
  182. resolve: false,
  183. for_user: user
  184. )
  185. result = List.first(results)
  186. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  187. end
  188. test "works with idna domains and bad chars in domain" do
  189. user = insert(:user, nickname: "lain@" <> to_string(:idna.encode("zetsubou.みんな")))
  190. results =
  191. User.search("lain@zetsubou!@#$%^&*()+,-/:;<=>?[]'_{}|~`.みんな",
  192. resolve: false,
  193. for_user: user
  194. )
  195. result = List.first(results)
  196. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  197. end
  198. test "works with idna domains and query as link" do
  199. user = insert(:user, nickname: "lain@" <> to_string(:idna.encode("zetsubou.みんな")))
  200. results =
  201. User.search("https://zetsubou.みんな/users/lain",
  202. resolve: false,
  203. for_user: user
  204. )
  205. result = List.first(results)
  206. assert user == result |> Map.put(:search_rank, nil) |> Map.put(:search_type, nil)
  207. end
  208. end
  209. end