1 defmodule Pleroma.Search.Meilisearch do
3 require Pleroma.Constants
7 import Pleroma.Search.DatabaseSearch
11 private_key = Pleroma.Config.get([Pleroma.Search.Meilisearch, :private_key])
13 [{"Content-Type", "application/json"}] ++
14 if is_nil(private_key), do: [], else: [{"X-Meili-API-Key", private_key}]
17 def meili_get(path) do
18 endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
22 Path.join(endpoint, path),
26 with {:ok, res} <- result do
27 {:ok, Jason.decode!(res.body)}
31 def meili_post(path, params) do
32 endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
36 Path.join(endpoint, path),
37 Jason.encode!(params),
41 with {:ok, res} <- result do
42 {:ok, Jason.decode!(res.body)}
46 def meili_put(path, params) do
47 endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
52 Path.join(endpoint, path),
53 Jason.encode!(params),
58 with {:ok, res} <- result do
59 {:ok, Jason.decode!(res.body)}
63 def meili_delete!(path) do
64 endpoint = Pleroma.Config.get([Pleroma.Search.Meilisearch, :url])
69 Path.join(endpoint, path),
76 def search(user, query, options \\ []) do
77 limit = Enum.min([Keyword.get(options, :limit), 40])
78 offset = Keyword.get(options, :offset, 0)
79 author = Keyword.get(options, :author)
83 "/indexes/objects/search",
84 %{q: query, offset: offset, limit: limit}
87 with {:ok, result} <- res do
88 hits = result["hits"] |> Enum.map(& &1["ap"])
92 |> Activity.create_by_object_ap_id()
93 |> Activity.with_preloaded_object()
94 |> Activity.with_preloaded_object()
95 |> Activity.restrict_deactivated_users()
96 |> maybe_restrict_local(user)
97 |> maybe_restrict_author(author)
98 |> maybe_restrict_blocked(user)
99 |> maybe_fetch(user, query)
100 |> order_by([object: obj], desc: obj.data["published"])
101 |> Pleroma.Repo.all()
103 _ -> maybe_fetch([], user, query)
108 def object_to_search_data(object) do
109 # Only index public or unlisted Notes
110 if not is_nil(object) and object.data["type"] == "Note" and
111 not is_nil(object.data["content"]) and
112 (Pleroma.Constants.as_public() in object.data["to"] or
113 Pleroma.Constants.as_public() in object.data["cc"]) and
114 String.length(object.data["content"]) > 1 do
118 case data["content"] do
119 [nil | rest] -> to_string(rest)
124 with {:ok, scrubbed} <- FastSanitize.strip_tags(content_str),
125 trimmed <- String.trim(scrubbed) do
129 if String.length(content) > 1 do
130 {:ok, published, _} = DateTime.from_iso8601(data["published"])
136 published: published |> DateTime.to_unix()
142 def add_to_index(activity) do
143 maybe_search_data = object_to_search_data(activity.object)
145 if activity.data["type"] == "Create" and maybe_search_data do
148 "/indexes/objects/documents",
152 with {:ok, res} <- result,
153 true <- Map.has_key?(res, "updateId") do
157 Logger.error("Failed to add activity #{activity.id} to index: #{inspect(result)}")
162 def remove_from_index(object) do
163 meili_delete!("/indexes/objects/documents/#{object.id}")