939f7f6cb36990515cb0fcebfd2d11b46943764c
[akkoma] / lib / pleroma / web / mastodon_api / search_controller.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.MastodonAPI.SearchController do
6 use Pleroma.Web, :controller
7
8 alias Pleroma.Activity
9 alias Pleroma.Plugs.RateLimiter
10 alias Pleroma.User
11 alias Pleroma.Web
12 alias Pleroma.Web.ControllerHelper
13 alias Pleroma.Web.MastodonAPI.AccountView
14 alias Pleroma.Web.MastodonAPI.StatusView
15
16 require Logger
17 plug(RateLimiter, :search when action in [:search, :search2, :account_search])
18
19 def search2(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
20 accounts = with_fallback(fn -> User.search(query, search_options(params, user)) end, [])
21 statuses = with_fallback(fn -> Activity.search(user, query) end, [])
22
23 tags_path = Web.base_url() <> "/tag/"
24
25 tags =
26 query
27 |> prepare_tags
28 |> Enum.map(fn tag -> %{name: tag, url: tags_path <> tag} end)
29
30 res = %{
31 "accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user),
32 "statuses" =>
33 StatusView.render("index.json", activities: statuses, for: user, as: :activity),
34 "hashtags" => tags
35 }
36
37 json(conn, res)
38 end
39
40 def search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
41 accounts = with_fallback(fn -> User.search(query, search_options(params, user)) end)
42 statuses = with_fallback(fn -> Activity.search(user, query) end)
43
44 tags = prepare_tags(query)
45
46 res = %{
47 "accounts" => AccountView.render("accounts.json", users: accounts, for: user, as: :user),
48 "statuses" =>
49 StatusView.render("index.json", activities: statuses, for: user, as: :activity),
50 "hashtags" => tags
51 }
52
53 json(conn, res)
54 end
55
56 def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do
57 accounts = User.search(query, search_options(params, user))
58 res = AccountView.render("accounts.json", users: accounts, for: user, as: :user)
59
60 json(conn, res)
61 end
62
63 defp prepare_tags(query) do
64 query
65 |> String.split()
66 |> Enum.uniq()
67 |> Enum.filter(fn tag -> String.starts_with?(tag, "#") end)
68 |> Enum.map(fn tag -> String.slice(tag, 1..-1) end)
69 end
70
71 defp search_options(params, user) do
72 [
73 resolve: params["resolve"] == "true",
74 following: params["following"] == "true",
75 limit: ControllerHelper.fetch_integer_param(params, "limit"),
76 offset: ControllerHelper.fetch_integer_param(params, "offset"),
77 for_user: user
78 ]
79 end
80
81 defp with_fallback(f, fallback \\ []) do
82 try do
83 f.()
84 rescue
85 error ->
86 Logger.error("#{__MODULE__} search error: #{inspect(error)}")
87 fallback
88 end
89 end
90 end