logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

database_search.ex (4694B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Search.DatabaseSearch do
  5. alias Pleroma.Activity
  6. alias Pleroma.Config
  7. alias Pleroma.Object.Fetcher
  8. alias Pleroma.Pagination
  9. alias Pleroma.User
  10. alias Pleroma.Web.ActivityPub.Visibility
  11. require Pleroma.Constants
  12. import Ecto.Query
  13. @behaviour Pleroma.Search.SearchBackend
  14. @impl true
  15. def search(user, search_query, options \\ []) do
  16. index_type = if Config.get([:database, :rum_enabled]), do: :rum, else: :gin
  17. limit = Enum.min([Keyword.get(options, :limit), 40])
  18. offset = Keyword.get(options, :offset, 0)
  19. author = Keyword.get(options, :author)
  20. search_function =
  21. if :persistent_term.get({Pleroma.Repo, :postgres_version}) >= 11 do
  22. :websearch
  23. else
  24. :plain
  25. end
  26. try do
  27. Activity
  28. |> Activity.with_preloaded_object()
  29. |> Activity.restrict_deactivated_users()
  30. |> restrict_public(user)
  31. |> query_with(index_type, search_query, search_function)
  32. |> maybe_restrict_local(user)
  33. |> maybe_restrict_author(author)
  34. |> maybe_restrict_blocked(user)
  35. |> Pagination.fetch_paginated(
  36. %{"offset" => offset, "limit" => limit, "skip_order" => index_type == :rum},
  37. :offset
  38. )
  39. |> maybe_fetch(user, search_query)
  40. rescue
  41. _ -> maybe_fetch([], user, search_query)
  42. end
  43. end
  44. @impl true
  45. def add_to_index(_activity), do: :ok
  46. @impl true
  47. def remove_from_index(_object), do: :ok
  48. def maybe_restrict_author(query, %User{} = author) do
  49. Activity.Queries.by_author(query, author)
  50. end
  51. def maybe_restrict_author(query, _), do: query
  52. def maybe_restrict_blocked(query, %User{} = user) do
  53. Activity.Queries.exclude_authors(query, User.blocked_users_ap_ids(user))
  54. end
  55. def maybe_restrict_blocked(query, _), do: query
  56. defp restrict_public(q, user) when not is_nil(user) do
  57. intended_recipients = [
  58. Pleroma.Constants.as_public(),
  59. Pleroma.Web.ActivityPub.Utils.as_local_public()
  60. ]
  61. from([a, o] in q,
  62. where: fragment("?->>'type' = 'Create'", a.data),
  63. where: fragment("? && ?", ^intended_recipients, a.recipients)
  64. )
  65. end
  66. defp restrict_public(q, _user) do
  67. from([a, o] in q,
  68. where: fragment("?->>'type' = 'Create'", a.data),
  69. where: ^Pleroma.Constants.as_public() in a.recipients
  70. )
  71. end
  72. defp query_with(q, :gin, search_query, :plain) do
  73. %{rows: [[tsc]]} =
  74. Ecto.Adapters.SQL.query!(
  75. Pleroma.Repo,
  76. "select current_setting('default_text_search_config')::regconfig::oid;"
  77. )
  78. from([a, o] in q,
  79. where:
  80. fragment(
  81. "to_tsvector(?::oid::regconfig, ?->>'content') @@ plainto_tsquery(?)",
  82. ^tsc,
  83. o.data,
  84. ^search_query
  85. )
  86. )
  87. end
  88. defp query_with(q, :gin, search_query, :websearch) do
  89. %{rows: [[tsc]]} =
  90. Ecto.Adapters.SQL.query!(
  91. Pleroma.Repo,
  92. "select current_setting('default_text_search_config')::regconfig::oid;"
  93. )
  94. from([a, o] in q,
  95. where:
  96. fragment(
  97. "to_tsvector(?::oid::regconfig, ?->>'content') @@ websearch_to_tsquery(?)",
  98. ^tsc,
  99. o.data,
  100. ^search_query
  101. )
  102. )
  103. end
  104. defp query_with(q, :rum, search_query, :plain) do
  105. from([a, o] in q,
  106. where:
  107. fragment(
  108. "? @@ plainto_tsquery(?)",
  109. o.fts_content,
  110. ^search_query
  111. ),
  112. order_by: [fragment("? <=> now()::date", o.inserted_at)]
  113. )
  114. end
  115. defp query_with(q, :rum, search_query, :websearch) do
  116. from([a, o] in q,
  117. where:
  118. fragment(
  119. "? @@ websearch_to_tsquery(?)",
  120. o.fts_content,
  121. ^search_query
  122. ),
  123. order_by: [fragment("? <=> now()::date", o.inserted_at)]
  124. )
  125. end
  126. def maybe_restrict_local(q, user) do
  127. limit = Config.get([:instance, :limit_to_local_content], :unauthenticated)
  128. case {limit, user} do
  129. {:all, _} -> restrict_local(q)
  130. {:unauthenticated, %User{}} -> q
  131. {:unauthenticated, _} -> restrict_local(q)
  132. {false, _} -> q
  133. end
  134. end
  135. defp restrict_local(q), do: where(q, local: true)
  136. def maybe_fetch(activities, user, search_query) do
  137. with true <- Regex.match?(~r/https?:/, search_query),
  138. {:ok, object} <- Fetcher.fetch_object_from_id(search_query),
  139. %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
  140. true <- Visibility.visible_for_user?(activity, user) do
  141. [activity | activities]
  142. else
  143. _ -> activities
  144. end
  145. end
  146. end