add copyright notice for forked files
[akkoma] / lib / pleroma / elasticsearch / store.ex
1 # Akkoma: A lightweight social networking server
2 # Copyright © 2022-2022 Akkoma Authors <https://git.ihatebeinga.live/IHBAGang/akkoma/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Elasticsearch do
6 alias Pleroma.Activity
7 alias Pleroma.User
8 alias Pleroma.Object
9 alias Pleroma.Elasticsearch.DocumentMappings
10 alias Pleroma.Config
11 require Logger
12
13 defp url do
14 Config.get([:elasticsearch, :url])
15 end
16
17 defp enabled? do
18 Config.get([:search, :provider]) == Pleroma.Search.Elasticsearch
19 end
20
21 def delete_by_id(:activity, id) do
22 if enabled?() do
23 Elastix.Document.delete(url(), "activities", "activity", id)
24 end
25 end
26
27 def put_by_id(:activity, id) do
28 id
29 |> Activity.get_by_id_with_object()
30 |> maybe_put_into_elasticsearch()
31 end
32
33 def maybe_put_into_elasticsearch({:ok, item}) do
34 maybe_put_into_elasticsearch(item)
35 end
36
37 def maybe_put_into_elasticsearch(
38 %{data: %{"type" => "Create"}, object: %{data: %{"type" => "Note"}}} = activity
39 ) do
40 if enabled?() do
41 actor = Pleroma.Activity.user_actor(activity)
42
43 activity
44 |> Map.put(:user_actor, actor)
45 |> put()
46 end
47 end
48
49 def maybe_put_into_elasticsearch(%User{actor_type: "Person"} = user) do
50 if enabled?() do
51 put(user)
52 end
53 end
54
55 def maybe_put_into_elasticsearch(_) do
56 {:ok, :skipped}
57 end
58
59 def maybe_bulk_post(data, type) do
60 if enabled?() do
61 bulk_post(data, type)
62 end
63 end
64
65 def put(%Activity{} = activity) do
66 with {:ok, _} <-
67 Elastix.Document.index(
68 url(),
69 "activities",
70 "activity",
71 DocumentMappings.Activity.id(activity),
72 DocumentMappings.Activity.encode(activity)
73 ) do
74 activity
75 |> Map.get(:object)
76 |> Object.hashtags()
77 |> Enum.map(fn x ->
78 %{id: x, name: x, timestamp: DateTime.to_iso8601(DateTime.utc_now())}
79 end)
80 |> bulk_post(:hashtags)
81 else
82 {:error, %{reason: err}} ->
83 Logger.error("Could not put activity: #{err}")
84 :skipped
85 end
86 end
87
88 def put(%User{} = user) do
89 with {:ok, _} <-
90 Elastix.Document.index(
91 url(),
92 "users",
93 "user",
94 DocumentMappings.User.id(user),
95 DocumentMappings.User.encode(user)
96 ) do
97 :ok
98 else
99 {:error, %{reason: err}} ->
100 Logger.error("Could not put user: #{err}")
101 :skipped
102 end
103 end
104
105 def bulk_post(data, :activities) do
106 d =
107 data
108 |> Enum.filter(fn x ->
109 t =
110 x.object
111 |> Map.get(:data, %{})
112 |> Map.get("type", "")
113
114 t == "Note"
115 end)
116 |> Enum.map(fn d ->
117 [
118 %{index: %{_id: DocumentMappings.Activity.id(d)}},
119 DocumentMappings.Activity.encode(d)
120 ]
121 end)
122 |> List.flatten()
123
124 with {:ok, %{body: %{"errors" => false}}} <-
125 Elastix.Bulk.post(
126 url(),
127 d,
128 index: "activities",
129 type: "activity"
130 ) do
131 :ok
132 else
133 {:error, %{reason: err}} ->
134 Logger.error("Could not bulk put activity: #{err}")
135 :skipped
136
137 {:ok, %{body: body}} ->
138 IO.inspect(body)
139 :skipped
140 end
141 end
142
143 def bulk_post(data, :users) do
144 d =
145 data
146 |> Enum.filter(fn x -> x.actor_type == "Person" end)
147 |> Enum.map(fn d ->
148 [
149 %{index: %{_id: DocumentMappings.User.id(d)}},
150 DocumentMappings.User.encode(d)
151 ]
152 end)
153 |> List.flatten()
154
155 with {:ok, %{body: %{"errors" => false}}} <-
156 Elastix.Bulk.post(
157 url(),
158 d,
159 index: "users",
160 type: "user"
161 ) do
162 :ok
163 else
164 {:error, %{reason: err}} ->
165 Logger.error("Could not bulk put users: #{err}")
166 :skipped
167
168 {:ok, %{body: body}} ->
169 IO.inspect(body)
170 :skipped
171 end
172 end
173
174 def bulk_post(data, :hashtags) when is_list(data) do
175 d =
176 data
177 |> Enum.map(fn d ->
178 [
179 %{index: %{_id: DocumentMappings.Hashtag.id(d)}},
180 DocumentMappings.Hashtag.encode(d)
181 ]
182 end)
183 |> List.flatten()
184
185 with {:ok, %{body: %{"errors" => false}}} <-
186 Elastix.Bulk.post(
187 url(),
188 d,
189 index: "hashtags",
190 type: "hashtag"
191 ) do
192 :ok
193 else
194 {:error, %{reason: err}} ->
195 Logger.error("Could not bulk put hashtags: #{err}")
196 :skipped
197
198 {:ok, %{body: body}} ->
199 IO.inspect(body)
200 :skipped
201 end
202 end
203
204 def bulk_post(_, :hashtags), do: {:ok, nil}
205
206 def search(_, _, _, :skip), do: []
207
208 def search(:raw, index, type, q) do
209 with {:ok, raw_results} <- Elastix.Search.search(url(), index, [type], q) do
210 results =
211 raw_results
212 |> Map.get(:body, %{})
213 |> Map.get("hits", %{})
214 |> Map.get("hits", [])
215
216 {:ok, results}
217 else
218 {:error, e} ->
219 Logger.error(e)
220 {:error, e}
221 end
222 end
223
224 def search(:activities, q) do
225 with {:ok, results} <- search(:raw, "activities", "activity", q) do
226 results
227 |> Enum.map(fn result -> result["_id"] end)
228 |> Pleroma.Activity.all_by_ids_with_object()
229 |> Enum.sort(&(&1.inserted_at >= &2.inserted_at))
230 else
231 e ->
232 Logger.error(e)
233 []
234 end
235 end
236
237 def search(:users, q) do
238 with {:ok, results} <- search(:raw, "users", "user", q) do
239 results
240 |> Enum.map(fn result -> result["_id"] end)
241 |> Pleroma.User.get_all_by_ids()
242 else
243 e ->
244 Logger.error(e)
245 []
246 end
247 end
248
249 def search(:hashtags, q) do
250 with {:ok, results} <- search(:raw, "hashtags", "hashtag", q) do
251 results
252 |> Enum.map(fn result -> result["_source"]["hashtag"] end)
253 else
254 e ->
255 Logger.error(e)
256 []
257 end
258 end
259 end