Add capabilities for emoji reactions
[akkoma] / lib / pleroma / search / elasticsearch.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.Search.Elasticsearch do
6 @behaviour Pleroma.Search
7
8 alias Pleroma.Activity
9 alias Pleroma.Object.Fetcher
10 alias Pleroma.Web.MastodonAPI.StatusView
11 alias Pleroma.Web.MastodonAPI.AccountView
12 alias Pleroma.Web.ActivityPub.Visibility
13 alias Pleroma.Search.Elasticsearch.Parsers
14 alias Pleroma.Web.Endpoint
15
16 def es_query(:activity, query) do
17 must = Parsers.Activity.parse(query)
18
19 if must == [] do
20 :skip
21 else
22 %{
23 size: 50,
24 terminate_after: 50,
25 timeout: "5s",
26 sort: [
27 "_score",
28 %{_timestamp: %{order: "desc", format: "basic_date_time"}}
29 ],
30 query: %{
31 bool: %{
32 must: must
33 }
34 }
35 }
36 end
37 end
38
39 def es_query(:user, query) do
40 must = Parsers.User.parse(query)
41
42 if must == [] do
43 :skip
44 else
45 %{
46 size: 50,
47 terminate_after: 50,
48 timeout: "5s",
49 sort: [
50 "_score"
51 ],
52 query: %{
53 bool: %{
54 must: must
55 }
56 }
57 }
58 end
59 end
60
61 def es_query(:hashtag, query) do
62 must = Parsers.Hashtag.parse(query)
63
64 if must == [] do
65 :skip
66 else
67 %{
68 size: 50,
69 terminate_after: 50,
70 timeout: "5s",
71 sort: [
72 "_score"
73 ],
74 query: %{
75 bool: %{
76 must: Parsers.Hashtag.parse(query)
77 }
78 }
79 }
80 end
81 end
82
83 defp maybe_fetch(:activity, search_query) do
84 with true <- Regex.match?(~r/https?:/, search_query),
85 {:ok, object} <- Fetcher.fetch_object_from_id(search_query),
86 %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]) do
87 activity
88 else
89 _ -> nil
90 end
91 end
92
93 @impl Pleroma.Search
94 def search(%{assigns: %{user: user}} = _conn, %{q: query} = _params, _options) do
95 parsed_query =
96 query
97 |> String.trim()
98 |> SearchParser.parse!()
99
100 activity_fetch_task =
101 Task.async(fn ->
102 maybe_fetch(:activity, String.trim(query))
103 end)
104
105 activity_task =
106 Task.async(fn ->
107 q = es_query(:activity, parsed_query)
108
109 Pleroma.Elasticsearch.search(:activities, q)
110 |> Enum.filter(fn x -> Visibility.visible_for_user?(x, user) end)
111 end)
112
113 user_task =
114 Task.async(fn ->
115 q = es_query(:user, parsed_query)
116
117 Pleroma.Elasticsearch.search(:users, q)
118 |> Enum.filter(fn x -> Pleroma.User.visible_for(x, user) == :visible end)
119 end)
120
121 hashtag_task =
122 Task.async(fn ->
123 q = es_query(:hashtag, parsed_query)
124
125 Pleroma.Elasticsearch.search(:hashtags, q)
126 end)
127
128 activity_results = Task.await(activity_task)
129 user_results = Task.await(user_task)
130 hashtag_results = Task.await(hashtag_task)
131 direct_activity = Task.await(activity_fetch_task)
132
133 activity_results =
134 if direct_activity == nil do
135 activity_results
136 else
137 [direct_activity | activity_results]
138 end
139
140 %{
141 "accounts" =>
142 AccountView.render("index.json",
143 users: user_results,
144 for: user
145 ),
146 "hashtags" =>
147 Enum.map(hashtag_results, fn x ->
148 %{
149 url: Endpoint.url() <> "/tag/" <> x,
150 name: x
151 }
152 end),
153 "statuses" =>
154 StatusView.render("index.json",
155 activities: activity_results,
156 for: user,
157 as: :activity
158 )
159 }
160 end
161 end