mirror of
https://github.com/philomena-dev/philomena.git
synced 2025-03-06 19:11: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
|
alias Philomena.Tags.Tag
|
||||||
import Ecto.Query
|
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 =
|
tags =
|
||||||
case extract_term(params) do
|
case extract_term(params) do
|
||||||
nil ->
|
{:error, _} ->
|
||||||
[]
|
[]
|
||||||
|
|
||||||
term ->
|
{:ok, term} ->
|
||||||
Tag
|
Tag
|
||||||
|> Search.search_definition(
|
|> Search.search_definition(
|
||||||
%{
|
%{
|
||||||
|
@ -39,12 +126,4 @@ defmodule PhilomenaWeb.Autocomplete.TagController do
|
||||||
conn
|
conn
|
||||||
|> json(tags)
|
|> json(tags)
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue