Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85827542
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Authored By
Unknown
Size
11 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex
index 7af7f460a..eed9fca1c 100644
--- a/lib/pleroma/search/meilisearch.ex
+++ b/lib/pleroma/search/meilisearch.ex
@@ -1,176 +1,182 @@
defmodule Pleroma.Search.Meilisearch do
require Logger
require Pleroma.Constants
alias Pleroma.Activity
+ alias Pleroma.Config.Getting, as: Config
import Pleroma.Search.DatabaseSearch
import Ecto.Query
@behaviour Pleroma.Search.SearchBackend
defp meili_headers do
- private_key = Pleroma.Config.get([Pleroma.Search.Meilisearch, :private_key])
+ private_key = Config.get([Pleroma.Search.Meilisearch, :private_key])
[{"Content-Type", "application/json"}] ++
if is_nil(private_key), do: [], else: [{"Authorization", "Bearer #{private_key}"}]
end
def meili_get(path) do
- endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
+ endpoint = Config.get([Pleroma.Search.Meilisearch, :url])
result =
Pleroma.HTTP.get(
Path.join(endpoint, path),
meili_headers()
)
with {:ok, res} <- result do
{:ok, Jason.decode!(res.body)}
end
end
def meili_post(path, params) do
- endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
+ endpoint = Config.get([Pleroma.Search.Meilisearch, :url])
result =
Pleroma.HTTP.post(
Path.join(endpoint, path),
Jason.encode!(params),
meili_headers()
)
with {:ok, res} <- result do
{:ok, Jason.decode!(res.body)}
end
end
def meili_put(path, params) do
- endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
+ endpoint = Config.get([Pleroma.Search.Meilisearch, :url])
result =
Pleroma.HTTP.request(
:put,
Path.join(endpoint, path),
Jason.encode!(params),
meili_headers(),
[]
)
with {:ok, res} <- result do
{:ok, Jason.decode!(res.body)}
end
end
def meili_delete(path) do
- endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
-
- Pleroma.HTTP.request(
- :delete,
- Path.join(endpoint, path),
- "",
- meili_headers(),
- []
- )
+ endpoint = Config.get([Pleroma.Search.Meilisearch, :url])
+
+ with {:ok, _} <-
+ Pleroma.HTTP.request(
+ :delete,
+ Path.join(endpoint, path),
+ "",
+ meili_headers(),
+ []
+ ) do
+ :ok
+ else
+ _ -> :error
+ end
end
@impl true
def search(user, query, options \\ []) do
limit = Enum.min([Keyword.get(options, :limit), 40])
offset = Keyword.get(options, :offset, 0)
author = Keyword.get(options, :author)
res =
meili_post(
"/indexes/objects/search",
%{q: query, offset: offset, limit: limit}
)
with {:ok, result} <- res do
hits = result["hits"] |> Enum.map(& &1["ap"])
try do
hits
|> Activity.create_by_object_ap_id()
|> Activity.with_preloaded_object()
|> Activity.restrict_deactivated_users()
|> maybe_restrict_local(user)
|> maybe_restrict_author(author)
|> maybe_restrict_blocked(user)
|> maybe_fetch(user, query)
|> order_by([object: obj], desc: obj.data["published"])
|> Pleroma.Repo.all()
rescue
_ -> maybe_fetch([], user, query)
end
end
end
def object_to_search_data(object) do
# Only index public or unlisted Notes
if not is_nil(object) and object.data["type"] == "Note" and
not is_nil(object.data["content"]) and
(Pleroma.Constants.as_public() in object.data["to"] or
Pleroma.Constants.as_public() in object.data["cc"]) and
object.data["content"] not in ["", "."] do
data = object.data
content_str =
case data["content"] do
[nil | rest] -> to_string(rest)
str -> str
end
content =
with {:ok, scrubbed} <-
FastSanitize.Sanitizer.scrub(content_str, Pleroma.HTML.Scrubber.SearchIndexing),
trimmed <- String.trim(scrubbed) do
trimmed
end
# Make sure we have a non-empty string
if content != "" do
{:ok, published, _} = DateTime.from_iso8601(data["published"])
%{
id: object.id,
content: content,
ap: data["id"],
published: published |> DateTime.to_unix()
}
end
end
end
@impl true
def add_to_index(activity) do
maybe_search_data = object_to_search_data(activity.object)
if activity.data["type"] == "Create" and maybe_search_data do
result =
meili_put(
"/indexes/objects/documents",
[maybe_search_data]
)
with {:ok, res} <- result,
true <- Map.has_key?(res, "updateId") do
# Added successfully
:ok
else
_ ->
# There was an error, report it
Logger.error("Failed to add activity #{activity.id} to index: #{inspect(result)}")
{:error, result}
end
else
# The post isn't something we can search, that's ok
:ok
end
end
@impl true
def remove_from_index(object) do
meili_delete("/indexes/objects/documents/#{object.id}")
end
end
diff --git a/lib/pleroma/workers/search_indexing_worker.ex b/lib/pleroma/workers/search_indexing_worker.ex
index 43b7bad1e..8476a2be5 100644
--- a/lib/pleroma/workers/search_indexing_worker.ex
+++ b/lib/pleroma/workers/search_indexing_worker.ex
@@ -1,21 +1,23 @@
defmodule Pleroma.Workers.SearchIndexingWorker do
use Pleroma.Workers.WorkerHelper, queue: "search_indexing"
@impl Oban.Worker
+ alias Pleroma.Config.Getting, as: Config
+
def perform(%Job{args: %{"op" => "add_to_index", "activity" => activity_id}}) do
activity = Pleroma.Activity.get_by_id_with_object(activity_id)
- search_module = Pleroma.Config.get([Pleroma.Search, :module])
+ search_module = Config.get([Pleroma.Search, :module])
search_module.add_to_index(activity)
end
def perform(%Job{args: %{"op" => "remove_from_index", "object" => object_id}}) do
object = Pleroma.Object.get_by_id(object_id)
- search_module = Pleroma.Config.get([Pleroma.Search, :module])
+ search_module = Config.get([Pleroma.Search, :module])
search_module.remove_from_index(object)
end
end
diff --git a/test/pleroma/search/meilisearch_test.exs b/test/pleroma/search/meilisearch_test.exs
index 04a2d75d9..3a267385d 100644
--- a/test/pleroma/search/meilisearch_test.exs
+++ b/test/pleroma/search/meilisearch_test.exs
@@ -1,129 +1,145 @@
# Pleroma: A lightweight social networking server
# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Search.MeilisearchTest do
require Pleroma.Constants
- use Pleroma.DataCase
+ use Pleroma.DataCase, async: true
use Oban.Testing, repo: Pleroma.Repo
import Pleroma.Factory
import Tesla.Mock
- import Mock
+ import Mox
alias Pleroma.Search.Meilisearch
alias Pleroma.Web.CommonAPI
alias Pleroma.Workers.SearchIndexingWorker
-
- setup_all do
- Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
- :ok
- end
+ alias Pleroma.UnstubbedConfigMock, as: Config
describe "meilisearch" do
- setup do: clear_config([Pleroma.Search, :module], Meilisearch)
-
- setup_with_mocks(
- [
- {Meilisearch, [:passthrough],
- [
- add_to_index: fn a -> passthrough([a]) end,
- remove_from_index: fn a -> passthrough([a]) end,
- meili_put: fn u, a -> passthrough([u, a]) end
- ]}
- ],
- context,
- do: {:ok, context}
- )
-
test "indexes a local post on creation" do
user = insert(:user)
- mock_global(fn
- %{method: :put, url: "http://127.0.0.1:7700/indexes/objects/documents", body: body} ->
+ Tesla.Mock.mock(fn
+ %{
+ method: :put,
+ url: "http://127.0.0.1:7700/indexes/objects/documents",
+ body: body
+ } ->
assert match?(
[%{"content" => "guys i just don't wanna leave the swamp"}],
Jason.decode!(body)
)
+ # To make sure that the worker is called
+ send(self(), "posted_to_meilisearch")
json(%{updateId: 1})
end)
+ Config
+ |> expect(:get, 3, fn
+ [Pleroma.Search, :module], nil ->
+ Meilisearch
+
+ [Pleroma.Search.Meilisearch, :url], nil ->
+ "http://127.0.0.1:7700"
+
+ [Pleroma.Search.Meilisearch, :private_key], nil ->
+ "secret"
+ end)
+
{:ok, activity} =
CommonAPI.post(user, %{
status: "guys i just don't wanna leave the swamp",
visibility: "public"
})
args = %{"op" => "add_to_index", "activity" => activity.id}
assert_enqueued(
worker: SearchIndexingWorker,
args: args
)
assert :ok = perform_job(SearchIndexingWorker, args)
-
- assert_called(Meilisearch.add_to_index(activity))
+ assert_received("posted_to_meilisearch")
end
test "doesn't index posts that are not public" do
user = insert(:user)
Enum.each(["private", "direct"], fn visibility ->
{:ok, activity} =
CommonAPI.post(user, %{
status: "guys i just don't wanna leave the swamp",
visibility: visibility
})
args = %{"op" => "add_to_index", "activity" => activity.id}
+ Config
+ |> expect(:get, fn
+ [Pleroma.Search, :module], nil ->
+ Meilisearch
+ end)
+
assert_enqueued(worker: SearchIndexingWorker, args: args)
assert :ok = perform_job(SearchIndexingWorker, args)
-
- assert_not_called(Meilisearch.meili_put(:_))
end)
-
- history = call_history(Meilisearch)
- assert Enum.count(history) == 2
end
test "deletes posts from index when deleted locally" do
user = insert(:user)
- mock_global(fn
- %{method: :put, url: "http://127.0.0.1:7700/indexes/objects/documents", body: body} ->
+ Tesla.Mock.mock(fn
+ %{
+ method: :put,
+ url: "http://127.0.0.1:7700/indexes/objects/documents",
+ body: body
+ } ->
assert match?(
[%{"content" => "guys i just don't wanna leave the swamp"}],
Jason.decode!(body)
)
json(%{updateId: 1})
%{method: :delete, url: "http://127.0.0.1:7700/indexes/objects/documents/" <> id} ->
+ send(self(), "called_delete")
assert String.length(id) > 1
json(%{updateId: 2})
end)
+ Config
+ |> expect(:get, 6, fn
+ [Pleroma.Search, :module], nil ->
+ Meilisearch
+
+ [Pleroma.Search.Meilisearch, :url], nil ->
+ "http://127.0.0.1:7700"
+
+ [Pleroma.Search.Meilisearch, :private_key], nil ->
+ "secret"
+ end)
+
{:ok, activity} =
CommonAPI.post(user, %{
status: "guys i just don't wanna leave the swamp",
visibility: "public"
})
args = %{"op" => "add_to_index", "activity" => activity.id}
assert_enqueued(worker: SearchIndexingWorker, args: args)
assert :ok = perform_job(SearchIndexingWorker, args)
{:ok, _} = CommonAPI.delete(activity.id, user)
delete_args = %{"op" => "remove_from_index", "object" => activity.object.id}
assert_enqueued(worker: SearchIndexingWorker, args: delete_args)
assert :ok = perform_job(SearchIndexingWorker, delete_args)
- assert_called(Meilisearch.remove_from_index(:_))
+ assert_received("called_delete")
end
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Oct 30, 8:50 PM (15 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1800537
Default Alt Text
(11 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline