philomena/lib/philomena/images/query.ex

166 lines
5.1 KiB
Elixir
Raw Normal View History

2019-08-24 17:35:30 +02:00
defmodule Philomena.Images.Query do
alias PhilomenaQuery.Parse.Parser
2019-11-02 21:31:55 +01:00
alias Philomena.Repo
2020-05-29 03:16:51 +02:00
defp gallery_id_transform(_ctx, value) do
case Integer.parse(value) do
2020-05-29 04:14:32 +02:00
{value, ""} when value >= 0 ->
{:ok, %{nested: %{path: :galleries, query: %{term: %{"galleries.id" => value}}}}}
_error ->
{:error, "Invalid gallery `#{value}'."}
2020-05-29 03:16:51 +02:00
end
end
2019-11-02 21:31:55 +01:00
defp user_my_transform(%{user: %{id: id}}, "faves"),
2019-11-02 21:31:55 +01:00
do: {:ok, %{term: %{favourited_by_user_ids: id}}}
defp user_my_transform(%{user: %{id: id}}, "upvotes"),
2019-11-02 21:31:55 +01:00
do: {:ok, %{term: %{upvoter_ids: id}}}
defp user_my_transform(%{user: %{id: id}}, "downvotes"),
2019-11-02 21:31:55 +01:00
do: {:ok, %{term: %{downvoter_ids: id}}}
defp user_my_transform(%{user: %{id: id}}, "uploads"),
2019-11-15 16:32:26 +01:00
do: {:ok, %{term: %{true_uploader_id: id}}}
defp user_my_transform(%{user: %{id: id}}, "hidden"),
2019-11-15 19:27:10 +01:00
do: {:ok, %{term: %{hidden_by_user_ids: id}}}
defp user_my_transform(%{watch: true}, "watched"),
2019-11-02 21:31:55 +01:00
do: {:error, "Recursive watchlists are not allowed."}
defp user_my_transform(%{user: user} = ctx, "watched") do
2019-11-02 21:31:55 +01:00
ctx = Map.merge(ctx, %{watch: true})
tag_include = %{terms: %{tag_ids: user.watched_tag_ids}}
include_query = invalid_filter_guard(ctx, user.watched_images_query_str)
exclude_query = invalid_filter_guard(ctx, user.watched_images_exclude_str)
2019-11-02 21:31:55 +01:00
should = [tag_include, include_query]
must_not = [exclude_query]
must_not =
if user.no_spoilered_in_watched do
user = user |> Repo.preload(:current_filter)
tag_exclude = %{terms: %{tag_ids: user.current_filter.spoilered_tag_ids}}
spoiler_query = invalid_filter_guard(ctx, user.current_filter.spoilered_complex_str)
2019-11-02 21:31:55 +01:00
[tag_exclude, spoiler_query | must_not]
else
must_not
2019-08-27 02:00:39 +02:00
end
2019-11-02 21:31:55 +01:00
2019-11-13 04:12:46 +01:00
{:ok, %{bool: %{should: should, must_not: must_not}}}
2019-11-02 21:31:55 +01:00
end
defp user_my_transform(_ctx, _value),
2019-11-02 21:31:55 +01:00
do: {:error, "Unknown `my' value."}
defp invalid_filter_guard(ctx, search_string) do
case parse(user_fields(), ctx, PhilomenaQuery.Parse.String.normalize(search_string)) do
{:ok, query} -> query
_error -> %{match_all: %{}}
end
end
2019-11-02 21:31:55 +01:00
2024-04-22 14:29:38 +02:00
defp tag_count_fields do
[
"body_type_tag_count",
"error_tag_count",
"character_tag_count",
"content_fanmade_tag_count",
"content_official_tag_count",
"oc_tag_count",
"origin_tag_count",
"rating_tag_count",
"species_tag_count",
"spoiler_tag_count"
]
end
defp anonymous_fields do
[
2020-01-11 05:20:19 +01:00
int_fields:
2024-07-23 14:58:49 +02:00
~W(id width height score upvotes downvotes faves uploader_id faved_by_id pixels size orig_size comment_count source_count tag_count) ++
2024-04-22 14:29:38 +02:00
tag_count_fields(),
2020-07-06 20:00:02 +02:00
float_fields: ~W(aspect_ratio wilson_score duration),
date_fields: ~W(created_at updated_at first_seen_at),
2020-01-11 05:20:19 +01:00
literal_fields:
~W(faved_by orig_sha512_hash sha512_hash uploader source_url original_format mime_type file_name),
2021-12-20 20:44:52 +01:00
bool_fields: ~W(animated processed thumbnails_generated),
ngram_fields: ~W(description),
custom_fields: ~W(gallery_id),
default_field: {"namespaced_tags.name", :term},
transforms: %{"gallery_id" => &gallery_id_transform/2},
aliases: %{
"faved_by" => "favourited_by_users",
"faved_by_id" => "favourited_by_user_ids"
},
no_downcase_fields: ~W(file_name)
]
2019-11-02 21:31:55 +01:00
end
defp user_fields do
fields = anonymous_fields()
2020-01-11 05:20:19 +01:00
Keyword.merge(fields,
custom_fields: fields[:custom_fields] ++ ~W(my),
transforms: Map.merge(fields[:transforms], %{"my" => &user_my_transform/2})
2020-01-11 05:20:19 +01:00
)
end
defp moderator_fields do
fields = user_fields()
2020-01-11 05:20:19 +01:00
Keyword.merge(fields,
int_fields:
fields[:int_fields] ++
~W(upvoted_by_id downvoted_by_id true_uploader_id hidden_by_id deleted_by_user_id),
literal_fields:
fields[:literal_fields] ++
~W(fingerprint upvoted_by downvoted_by true_uploader hidden_by deleted_by_user),
2020-02-01 17:04:11 +01:00
ngram_fields: fields[:ngram_fields] ++ ~W(deletion_reason),
ip_fields: ~W(ip),
2021-12-20 20:44:52 +01:00
bool_fields: fields[:bool_fields] ++ ~W(deleted),
2020-01-11 05:20:19 +01:00
aliases:
Map.merge(fields[:aliases], %{
"upvoted_by" => "upvoters",
"downvoted_by" => "downvoters",
"upvoted_by_id" => "upvoter_ids",
"downvoted_by_id" => "downvoter_ids",
"hidden_by" => "hidden_by_users",
"hidden_by_id" => "hidden_by_user_ids",
"deleted" => "hidden_from_users"
})
)
2019-11-02 21:31:55 +01:00
end
defp parse(fields, context, query_string) do
fields
|> Parser.new()
|> Parser.parse(query_string, context)
2019-11-02 21:31:55 +01:00
end
def compile(query_string, opts \\ []) do
user = Keyword.get(opts, :user)
watch = Keyword.get(opts, :watch, false)
2019-08-29 03:14:54 +02:00
case user do
nil ->
parse(anonymous_fields(), %{user: nil, watch: watch}, query_string)
2019-08-29 03:14:54 +02:00
%{role: role} when role in ~W(user assistant) ->
parse(user_fields(), %{user: user, watch: watch}, query_string)
2019-08-29 03:14:54 +02:00
%{role: role} when role in ~W(moderator admin) ->
parse(moderator_fields(), %{user: user, watch: watch}, query_string)
2019-08-29 03:14:54 +02:00
_ ->
raise ArgumentError, "Unknown user role."
end
end
2019-08-26 15:57:04 +02:00
end