mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +01:00
tag query names correctly
This commit is contained in:
parent
1d23b9be55
commit
5dc4181014
3 changed files with 75 additions and 40 deletions
|
@ -8,27 +8,42 @@ defmodule Philomena.SpoilerExecutor do
|
|||
import Ecto.Query
|
||||
import Philomena.Search.String
|
||||
|
||||
@complex_tag "complex"
|
||||
@hidden_tag "hidden"
|
||||
|
||||
@doc """
|
||||
Compile a filter's spoiler context for the purpose of executing it as
|
||||
a spoiler. This logic is different from filter execution because it
|
||||
tags query leaves with relevant information about which aspect of the
|
||||
spoiler they match (tag match, complex filter match).
|
||||
spoiler they match (tag spoiler match, complex spoiler match).
|
||||
"""
|
||||
@spec compile_spoiler(map(), map()) :: map()
|
||||
def compile_spoiler(user, filter) do
|
||||
spoilered_tags =
|
||||
Enum.map(filter.spoilered_tag_ids, fn id ->
|
||||
%{term: %{tag_id: id}, _name: Integer.to_string(id)}
|
||||
%{term: %{tag_ids: %{value: id, _name: Integer.to_string(id)}}}
|
||||
end)
|
||||
|
||||
spoilered_complex =
|
||||
user
|
||||
|> invalid_filter_guard(filter.spoilered_complex_str)
|
||||
|> Map.put(:_name, "complex")
|
||||
spoilered_complex = %{
|
||||
bool: %{
|
||||
must: invalid_filter_guard(user, filter.spoilered_complex_str),
|
||||
_name: @complex_tag
|
||||
}
|
||||
}
|
||||
|
||||
hides = %{
|
||||
bool: %{
|
||||
must: [
|
||||
invalid_filter_guard(user, filter.hidden_complex_str),
|
||||
%{terms: %{tag_ids: filter.hidden_tag_ids}}
|
||||
],
|
||||
_name: @hidden_tag
|
||||
}
|
||||
}
|
||||
|
||||
%{
|
||||
bool: %{
|
||||
should: [spoilered_complex | spoilered_tags]
|
||||
should: [hides, spoilered_complex | spoilered_tags]
|
||||
}
|
||||
}
|
||||
end
|
||||
|
@ -39,19 +54,28 @@ defmodule Philomena.SpoilerExecutor do
|
|||
the spoiler matched, or the atom :complex if the complex spoiler matched
|
||||
instead of any tag object.
|
||||
"""
|
||||
@spec execute_spoiler(map(), list()) :: %{optional(integer()) => [map()] | :complex}
|
||||
@spec execute_spoiler(map(), list()) :: %{optional(integer()) => [map()] | :complex | :hidden}
|
||||
def execute_spoiler(compiled, images) do
|
||||
image_ids = %{
|
||||
image_ids = extract_ids(images)
|
||||
|
||||
image_terms = %{
|
||||
terms: %{id: extract_ids(images)}
|
||||
}
|
||||
|
||||
test_query = %{
|
||||
query: %{
|
||||
bool: %{
|
||||
must: [compiled, image_ids],
|
||||
must: [compiled, image_terms]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results = Elasticsearch.search_results(Image, test_query)
|
||||
pagination_params = %{
|
||||
page_number: 1,
|
||||
page_size: length(image_ids)
|
||||
}
|
||||
|
||||
results = Elasticsearch.search_results(Image, test_query, pagination_params)
|
||||
|
||||
tags = extract_tags(results.entries)
|
||||
|
||||
|
@ -95,7 +119,7 @@ defmodule Philomena.SpoilerExecutor do
|
|||
defp extract_tags(results) do
|
||||
hit_tag_ids =
|
||||
results
|
||||
|> Enum.flat_map(fn {_id, hit} -> hit["matched_queries"] end)
|
||||
|> Enum.flat_map(fn {_id, hit} -> filter_special_matched(hit["matched_queries"]) end)
|
||||
|> Enum.uniq()
|
||||
|
||||
Tag
|
||||
|
@ -106,10 +130,15 @@ defmodule Philomena.SpoilerExecutor do
|
|||
|
||||
# Create a map key for the response of execute_spoiler/2. Determines
|
||||
# the reason an image was in this response.
|
||||
@spec filter_reason({integer(), map()}, map()) :: {integer(), [map()] | :complex}
|
||||
@spec filter_reason({integer(), map()}, map()) :: {integer(), [map()] | :complex | :hidden}
|
||||
defp filter_reason({id, hit}, tags) do
|
||||
matched_queries = hit["matched_queries"]
|
||||
|
||||
if Enum.member?(matched_queries, @hidden_tag) do
|
||||
{id, :hidden}
|
||||
else
|
||||
tags
|
||||
|> Map.take(hit["matched_queries"])
|
||||
|> Map.take(matched_queries)
|
||||
|> Enum.sort(&tag_sort/2)
|
||||
|> case do
|
||||
[] ->
|
||||
|
@ -119,6 +148,7 @@ defmodule Philomena.SpoilerExecutor do
|
|||
{id, matched_tags}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# The logic for tag sorting is as follows:
|
||||
# 1. If both tags have a spoiler image, sort by images count asc
|
||||
|
@ -140,4 +170,11 @@ defmodule Philomena.SpoilerExecutor do
|
|||
true
|
||||
end
|
||||
end
|
||||
|
||||
# The list of matched queries may return things which do not look like
|
||||
# integer IDs and will cause Postgrex to choke; filter those out here.
|
||||
@spec filter_special_matched(list()) :: list()
|
||||
defp filter_special_matched(matched_queries) do
|
||||
Enum.filter(matched_queries, &String.match?(&1, ~r/\A\d+\z/))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -57,6 +57,8 @@ defmodule PhilomenaWeb.ActivityController do
|
|||
Comment |> preload([:user, image: [:tags]])
|
||||
)
|
||||
|
||||
comment_images = Enum.map(comments, & &1.image)
|
||||
|
||||
watched =
|
||||
if !!user do
|
||||
{:ok, {watched_images, _tags}} =
|
||||
|
@ -106,7 +108,7 @@ defmodule PhilomenaWeb.ActivityController do
|
|||
spoilers =
|
||||
SpoilerExecutor.execute_spoiler(
|
||||
conn.assigns.compiled_spoiler,
|
||||
[images, top_scoring, watched, featured_image]
|
||||
[images, top_scoring, watched, featured_image, comment_images]
|
||||
)
|
||||
|
||||
render(
|
||||
|
|
|
@ -236,29 +236,25 @@ defmodule PhilomenaWeb.ImageView do
|
|||
}
|
||||
end
|
||||
|
||||
def filter_or_spoiler_value(conn, image) do
|
||||
spoilered(conn)[image.id]
|
||||
end
|
||||
|
||||
def filter_or_spoiler_hits?(conn, image) do
|
||||
tag_filter_or_spoiler_hits?(conn, image) or complex_filter_or_spoiler_hits?(conn, image)
|
||||
Map.has_key?(spoilered(conn), image.id)
|
||||
end
|
||||
|
||||
defp tag_filter_or_spoiler_hits?(conn, image) do
|
||||
filter = conn.assigns.current_filter
|
||||
filtered_tag_ids = MapSet.new(filter.spoilered_tag_ids ++ filter.hidden_tag_ids)
|
||||
image_tag_ids = MapSet.new(image.tags, & &1.id)
|
||||
|
||||
MapSet.size(MapSet.intersection(filtered_tag_ids, image_tag_ids)) > 0
|
||||
def filter_hits?(conn, image) do
|
||||
spoilered(conn)[image.id] == :hidden
|
||||
end
|
||||
|
||||
defp complex_filter_or_spoiler_hits?(conn, image) do
|
||||
doc = image_filter_data(image)
|
||||
complex_filter = conn.assigns.compiled_complex_filter
|
||||
complex_spoiler = conn.assigns.compiled_complex_spoiler
|
||||
def spoiler_hits?(conn, image) do
|
||||
spoilered = spoilered(conn)
|
||||
|
||||
query = %{
|
||||
bool: %{
|
||||
should: [complex_filter, complex_spoiler]
|
||||
}
|
||||
}
|
||||
is_list(spoilered[image.id]) or spoilered[image.id] == :complex
|
||||
end
|
||||
|
||||
Philomena.Search.Evaluator.hits?(doc, query)
|
||||
defp spoilered(conn) do
|
||||
Map.get(conn.assigns, :spoilered, %{})
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue