mirror of
https://github.com/philomena-dev/philomena.git
synced 2025-03-06 11:01:27 +01:00
Merge pull request #436 from MareStare/feat/server-side-suggestions-api-v2
[Part 1] Add server-side suggestions API v2
This commit is contained in:
commit
6d5f45af4f
1 changed files with 90 additions and 11 deletions
|
@ -5,13 +5,100 @@ defmodule PhilomenaWeb.Autocomplete.TagController do
|
|||
alias Philomena.Tags.Tag
|
||||
import Ecto.Query
|
||||
|
||||
def show(conn, params) do
|
||||
def show(conn, %{"vsn" => "2"} = params), do: show_v2(conn, params)
|
||||
def show(conn, params), do: show_v1(conn, params)
|
||||
|
||||
# Returns a list of tag suggestions for an incomplete term. Does a prefix search
|
||||
# on the canonical tag names and their aliases.
|
||||
#
|
||||
# See the docs on `show_v1` for the explanation on the breaking change we made
|
||||
# in the `v2` version.
|
||||
defp show_v2(conn, params) do
|
||||
with {:ok, term} <- extract_term(params),
|
||||
{:ok, limit} <- extract_limit(params) do
|
||||
suggestions = search(term, limit)
|
||||
json(conn, %{suggestions: suggestions})
|
||||
else
|
||||
{:error, message} ->
|
||||
conn
|
||||
|> put_status(:unprocessable_entity)
|
||||
|> json(%{error: message})
|
||||
end
|
||||
end
|
||||
|
||||
defp extract_term(%{"term" => term}) when is_binary(term) and byte_size(term) > 2 do
|
||||
result =
|
||||
term
|
||||
|> String.downcase()
|
||||
|> String.trim()
|
||||
|
||||
{:ok, result}
|
||||
end
|
||||
|
||||
defp extract_term(%{"term" => _}),
|
||||
do: {:error, "Term is too short, must be at least 3 characters"}
|
||||
|
||||
defp extract_term(_params), do: {:error, "Term is missing"}
|
||||
|
||||
defp extract_limit(params) do
|
||||
limit =
|
||||
params
|
||||
|> Map.get("limit", "10")
|
||||
|> Integer.parse()
|
||||
|
||||
case limit do
|
||||
{limit, ""} when limit > 0 and limit <= 10 ->
|
||||
{:ok, limit}
|
||||
|
||||
_ ->
|
||||
{:error, "Limit must be an integer between 1 and 10"}
|
||||
end
|
||||
end
|
||||
|
||||
@spec search(String.t(), integer()) :: [map()]
|
||||
defp search(term, limit) do
|
||||
Tag
|
||||
|> Search.search_definition(
|
||||
%{
|
||||
query: %{
|
||||
bool: %{
|
||||
should: [
|
||||
%{prefix: %{name: term}},
|
||||
%{prefix: %{name_in_namespace: term}}
|
||||
]
|
||||
}
|
||||
},
|
||||
sort: %{images: :desc}
|
||||
},
|
||||
%{page_size: 10}
|
||||
)
|
||||
|> Search.search_records(preload(Tag, :aliased_tag))
|
||||
|> Enum.map(
|
||||
&%{
|
||||
:alias => if(is_nil(&1.aliased_tag), do: nil, else: &1.name),
|
||||
canonical: if(is_nil(&1.aliased_tag), do: &1.name, else: &1.aliased_tag.name),
|
||||
images: if(is_nil(&1.aliased_tag), do: &1.images_count, else: &1.aliased_tag.images_count)
|
||||
}
|
||||
)
|
||||
|> Enum.filter(&(&1.images > 0))
|
||||
|> Enum.take(limit)
|
||||
end
|
||||
|
||||
# Version 1 is kept for backwards compatibility with the older versions of
|
||||
# the frontend application that may still be cached in user's browsers. Don't
|
||||
# change this code! All the new development should be done in the `v2` version.
|
||||
#
|
||||
# The problem of `v1` was that it was doing the work of formatting the completion
|
||||
# results on the backend, which was not ideal. So instead, the `v2` version
|
||||
# was created to return the raw data in fully structured JSON format, which
|
||||
# the frontend application can then format and style as needed.
|
||||
defp show_v1(conn, params) do
|
||||
tags =
|
||||
case extract_term(params) do
|
||||
nil ->
|
||||
{:error, _} ->
|
||||
[]
|
||||
|
||||
term ->
|
||||
{:ok, term} ->
|
||||
Tag
|
||||
|> Search.search_definition(
|
||||
%{
|
||||
|
@ -39,12 +126,4 @@ defmodule PhilomenaWeb.Autocomplete.TagController do
|
|||
conn
|
||||
|> json(tags)
|
||||
end
|
||||
|
||||
defp extract_term(%{"term" => term}) when is_binary(term) and byte_size(term) > 2 do
|
||||
term
|
||||
|> String.downcase()
|
||||
|> String.trim()
|
||||
end
|
||||
|
||||
defp extract_term(_params), do: nil
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue