2019-12-01 03:22:05 +01:00
|
|
|
defmodule PhilomenaWeb.ImageLoader do
|
2019-12-24 22:14:42 +01:00
|
|
|
alias Philomena.Elasticsearch
|
2019-12-01 03:22:05 +01:00
|
|
|
alias Philomena.Images.{Image, Query}
|
2019-12-05 22:57:59 +01:00
|
|
|
alias Philomena.Textile.Renderer
|
|
|
|
alias Philomena.Tags.Tag
|
|
|
|
alias Philomena.Repo
|
2019-12-01 03:22:05 +01:00
|
|
|
import Ecto.Query
|
|
|
|
|
|
|
|
def search_string(conn, search_string, options \\ []) do
|
|
|
|
user = conn.assigns.current_user
|
|
|
|
|
|
|
|
with {:ok, tree} <- Query.compile(user, search_string) do
|
|
|
|
{:ok, query(conn, tree, options)}
|
|
|
|
else
|
|
|
|
error ->
|
|
|
|
error
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def query(conn, body, options \\ []) do
|
2019-12-26 23:43:32 +01:00
|
|
|
sort_queries = Keyword.get(options, :queries, [])
|
|
|
|
sort_sorts = Keyword.get(options, :sorts, [%{created_at: :desc}])
|
|
|
|
pagination = Keyword.get(options, :pagination, conn.assigns.image_pagination)
|
|
|
|
queryable = Keyword.get(options, :queryable, Image |> preload(:tags))
|
|
|
|
constant_score = Keyword.get(options, :constant_score, true)
|
2019-12-01 03:22:05 +01:00
|
|
|
|
2019-12-27 00:58:52 +01:00
|
|
|
tags =
|
|
|
|
body
|
|
|
|
|> search_tag_names()
|
|
|
|
|> load_tags()
|
|
|
|
|> render_bodies(conn)
|
|
|
|
|
2019-12-01 03:22:05 +01:00
|
|
|
user = conn.assigns.current_user
|
|
|
|
filter = conn.assigns.compiled_filter
|
2019-12-18 01:42:50 +01:00
|
|
|
filters = create_filters(conn, user, filter)
|
2019-12-26 23:43:32 +01:00
|
|
|
body = maybe_constant_score(body, constant_score)
|
2019-12-05 22:57:59 +01:00
|
|
|
records =
|
2019-12-24 22:14:42 +01:00
|
|
|
Elasticsearch.search_records(
|
|
|
|
Image,
|
2019-12-05 22:57:59 +01:00
|
|
|
%{
|
|
|
|
query: %{
|
|
|
|
bool: %{
|
|
|
|
must: List.flatten([body, sort_queries]),
|
|
|
|
must_not: filters
|
|
|
|
}
|
|
|
|
},
|
|
|
|
sort: sort_sorts
|
2019-12-01 03:22:05 +01:00
|
|
|
},
|
2019-12-05 22:57:59 +01:00
|
|
|
pagination,
|
|
|
|
queryable
|
|
|
|
)
|
|
|
|
|
|
|
|
{records, tags}
|
2019-12-01 03:22:05 +01:00
|
|
|
end
|
|
|
|
|
2019-12-18 01:42:50 +01:00
|
|
|
defp create_filters(conn, user, filter) do
|
|
|
|
show_hidden? = Canada.Can.can?(user, :hide, %Image{})
|
|
|
|
del = conn.params["del"]
|
|
|
|
hidden = conn.params["hidden"]
|
|
|
|
|
2019-12-01 03:22:05 +01:00
|
|
|
[
|
2019-12-18 01:42:50 +01:00
|
|
|
filter
|
2019-12-01 03:22:05 +01:00
|
|
|
]
|
2019-12-18 01:42:50 +01:00
|
|
|
|> maybe_show_deleted(show_hidden?, del)
|
|
|
|
|> maybe_custom_hide(user, hidden)
|
2019-12-01 03:22:05 +01:00
|
|
|
end
|
|
|
|
|
2019-12-18 01:42:50 +01:00
|
|
|
# Allow moderators to index hidden images
|
|
|
|
|
|
|
|
defp maybe_show_deleted(filters, false, _param),
|
|
|
|
do: [%{term: %{hidden_from_users: true}} | filters]
|
|
|
|
|
|
|
|
defp maybe_show_deleted(filters, true, "1"),
|
|
|
|
do: filters
|
|
|
|
|
|
|
|
defp maybe_show_deleted(filters, true, "only"),
|
|
|
|
do: [%{term: %{hidden_from_users: false}} | filters]
|
|
|
|
|
2019-12-19 23:39:34 +01:00
|
|
|
defp maybe_show_deleted(filters, true, "deleted"),
|
|
|
|
do: [%{term: %{hidden_from_users: false}}, %{exists: %{field: :duplicate_id}} | filters]
|
|
|
|
|
2019-12-18 01:42:50 +01:00
|
|
|
defp maybe_show_deleted(filters, true, _param),
|
|
|
|
do: [%{term: %{hidden_from_users: true}} | filters]
|
|
|
|
|
|
|
|
# Allow users to reverse the effect of hiding images,
|
|
|
|
# if desired
|
|
|
|
|
2019-12-18 01:44:26 +01:00
|
|
|
defp maybe_custom_hide(filters, %{id: _id}, "1"),
|
2019-12-18 01:42:50 +01:00
|
|
|
do: filters
|
|
|
|
|
|
|
|
defp maybe_custom_hide(filters, %{id: id}, _param),
|
2019-12-01 03:22:05 +01:00
|
|
|
do: [%{term: %{hidden_by_user_ids: id}} | filters]
|
|
|
|
|
2019-12-18 01:42:50 +01:00
|
|
|
defp maybe_custom_hide(filters, _user, _param),
|
2019-12-01 03:22:05 +01:00
|
|
|
do: filters
|
2019-12-05 22:57:59 +01:00
|
|
|
|
2019-12-26 23:43:32 +01:00
|
|
|
defp maybe_constant_score(body, false), do: body
|
|
|
|
defp maybe_constant_score(body, _), do: %{bool: %{filter: body}}
|
|
|
|
|
2019-12-05 22:57:59 +01:00
|
|
|
# TODO: the search parser should try to optimize queries
|
|
|
|
defp search_tag_name(%{term: %{"namespaced_tags.name" => tag_name}}), do: [tag_name]
|
|
|
|
defp search_tag_name(_other_query), do: []
|
|
|
|
|
|
|
|
defp search_tag_names(%{bool: %{must: musts}}), do: Enum.flat_map(musts, &search_tag_name(&1))
|
|
|
|
defp search_tag_names(%{bool: %{should: shoulds}}), do: Enum.flat_map(shoulds, &search_tag_name(&1))
|
|
|
|
defp search_tag_names(%{term: %{"namespaced_tags.name" => tag_name}}), do: [tag_name]
|
|
|
|
defp search_tag_names(_other_query), do: []
|
|
|
|
|
|
|
|
defp load_tags([]), do: []
|
|
|
|
defp load_tags(tags) do
|
|
|
|
Tag
|
|
|
|
|> join(:left, [t], at in Tag, on: t.id == at.aliased_tag_id)
|
|
|
|
|> where([t, at], t.name in ^tags or at.name in ^tags)
|
2019-12-31 00:56:29 +01:00
|
|
|
|> preload([:aliases, :aliased_tag, :implied_tags, :implied_by_tags, :dnp_entries, public_links: :user, hidden_links: :user])
|
2019-12-05 22:57:59 +01:00
|
|
|
|> Repo.all()
|
2019-12-08 02:56:08 +01:00
|
|
|
|> Enum.uniq_by(& &1.id)
|
2019-12-08 03:00:36 +01:00
|
|
|
|> Enum.filter(&is_nil(&1.aliased_tag))
|
2019-12-08 19:04:06 +01:00
|
|
|
|> Tag.display_order()
|
2019-12-05 22:57:59 +01:00
|
|
|
end
|
|
|
|
|
2019-12-05 23:01:09 +01:00
|
|
|
defp render_bodies([], _conn), do: []
|
|
|
|
defp render_bodies([tag], conn) do
|
2019-12-05 22:57:59 +01:00
|
|
|
dnp_bodies =
|
|
|
|
Renderer.render_collection(Enum.map(tag.dnp_entries, &%{body: &1.conditions || ""}), conn)
|
|
|
|
|
|
|
|
dnp_entries =
|
|
|
|
Enum.zip(dnp_bodies, tag.dnp_entries)
|
|
|
|
|
2019-12-05 23:01:09 +01:00
|
|
|
description =
|
2019-12-05 23:01:47 +01:00
|
|
|
Renderer.render_one(%{body: tag.description || ""}, conn)
|
2019-12-05 23:01:09 +01:00
|
|
|
|
|
|
|
[{tag, description, dnp_entries}]
|
2019-12-05 22:57:59 +01:00
|
|
|
end
|
2019-12-05 23:01:09 +01:00
|
|
|
defp render_bodies(tags, _conn), do: tags
|
2019-12-18 01:42:50 +01:00
|
|
|
end
|