229 lines
5.9 KiB
Ruby
229 lines
5.9 KiB
Ruby
|
|
class WorkSearchForm
|
||
|
|
|
||
|
|
extend ActiveModel::Naming
|
||
|
|
include ActiveModel::Conversion
|
||
|
|
include ActiveModel::Validations
|
||
|
|
|
||
|
|
ATTRIBUTES = [
|
||
|
|
:query,
|
||
|
|
:title,
|
||
|
|
:creators,
|
||
|
|
:collected,
|
||
|
|
:faceted,
|
||
|
|
:revised_at,
|
||
|
|
:language_id,
|
||
|
|
:complete,
|
||
|
|
:crossover,
|
||
|
|
:single_chapter,
|
||
|
|
:word_count,
|
||
|
|
:hits,
|
||
|
|
:kudos_count,
|
||
|
|
:bookmarks_count,
|
||
|
|
:comments_count,
|
||
|
|
:pseud_ids,
|
||
|
|
:collection_ids,
|
||
|
|
:tag,
|
||
|
|
:excluded_tag_names,
|
||
|
|
:excluded_tag_ids,
|
||
|
|
:other_tag_names,
|
||
|
|
:filter_ids,
|
||
|
|
:fandom_names,
|
||
|
|
:fandom_ids,
|
||
|
|
:rating_ids,
|
||
|
|
:category_ids,
|
||
|
|
:archive_warning_ids,
|
||
|
|
:character_names,
|
||
|
|
:character_ids,
|
||
|
|
:relationship_names,
|
||
|
|
:relationship_ids,
|
||
|
|
:freeform_names,
|
||
|
|
:freeform_ids,
|
||
|
|
:date_from,
|
||
|
|
:date_to,
|
||
|
|
:words_from,
|
||
|
|
:words_to,
|
||
|
|
:sort_column,
|
||
|
|
:sort_direction,
|
||
|
|
:page
|
||
|
|
].freeze
|
||
|
|
|
||
|
|
attr_accessor :options
|
||
|
|
|
||
|
|
ATTRIBUTES.each do |filterable|
|
||
|
|
define_method(filterable) { options[filterable] }
|
||
|
|
end
|
||
|
|
|
||
|
|
def initialize(opts={})
|
||
|
|
@options = opts
|
||
|
|
process_options
|
||
|
|
@searcher = WorkQuery.new(@options)
|
||
|
|
end
|
||
|
|
|
||
|
|
def process_options
|
||
|
|
@options.delete_if { |k, v| v == "0" || v.blank? }
|
||
|
|
standardize_creator_queries
|
||
|
|
standardize_language_ids
|
||
|
|
set_sorting
|
||
|
|
clean_up_angle_brackets
|
||
|
|
rename_warning_field
|
||
|
|
end
|
||
|
|
|
||
|
|
# Make the creator/creators change backwards compatible
|
||
|
|
def standardize_creator_queries
|
||
|
|
return unless @options[:query].present?
|
||
|
|
@options[:query] = @options[:query].gsub('creator:', 'creators:')
|
||
|
|
end
|
||
|
|
|
||
|
|
def standardize_language_ids
|
||
|
|
# Maintain backward compatibility for old work searches/filters:
|
||
|
|
|
||
|
|
# - Using language IDs in the "Language" dropdown
|
||
|
|
if @options[:language_id].present? && @options[:language_id].to_i != 0
|
||
|
|
language = Language.find_by(id: options[:language_id])
|
||
|
|
options[:language_id] = language.short if language.present?
|
||
|
|
end
|
||
|
|
|
||
|
|
# - Using language IDs in "Any field" (search) or "Search within results" (filters)
|
||
|
|
if @options[:query].present?
|
||
|
|
@options[:query] = @options[:query].gsub(/\blanguage_id\s*:\s*(\d+)/) do
|
||
|
|
lang = Language.find_by(id: Regexp.last_match[1])
|
||
|
|
lang = Language.default if lang.blank?
|
||
|
|
"language_id: " + lang.short
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def set_sorting
|
||
|
|
@options[:sort_column] ||= default_sort_column
|
||
|
|
@options[:sort_direction] ||= default_sort_direction
|
||
|
|
end
|
||
|
|
|
||
|
|
def clean_up_angle_brackets
|
||
|
|
[:word_count, :hits, :kudos_count, :comments_count, :bookmarks_count, :revised_at, :query].each do |countable|
|
||
|
|
next unless @options[countable].present?
|
||
|
|
str = @options[countable]
|
||
|
|
@options[countable] = str.gsub(">", ">").gsub("<", "<")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def rename_warning_field
|
||
|
|
if @options[:warning_ids].present?
|
||
|
|
@options[:archive_warning_ids] = @options.delete(:warning_ids)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
def persisted?
|
||
|
|
false
|
||
|
|
end
|
||
|
|
|
||
|
|
def summary
|
||
|
|
summary = []
|
||
|
|
if @options[:query].present?
|
||
|
|
summary << @options[:query].gsub('creators:', 'creator:')
|
||
|
|
end
|
||
|
|
if @options[:title].present?
|
||
|
|
summary << "Title: #{@options[:title]}"
|
||
|
|
end
|
||
|
|
if @options[:creators].present?
|
||
|
|
summary << "Creator: #{@options[:creators]}"
|
||
|
|
end
|
||
|
|
tags = @searcher.included_tag_names
|
||
|
|
all_tag_ids = @searcher.filter_ids
|
||
|
|
unless all_tag_ids.empty?
|
||
|
|
tags << Tag.where(id: all_tag_ids).pluck(:name).join(", ")
|
||
|
|
end
|
||
|
|
unless tags.empty?
|
||
|
|
summary << "Tags: #{tags.uniq.join(", ")}"
|
||
|
|
end
|
||
|
|
if complete.to_s == "T"
|
||
|
|
summary << "Complete"
|
||
|
|
elsif complete.to_s == "F"
|
||
|
|
summary << "Incomplete"
|
||
|
|
end
|
||
|
|
if crossover.to_s == "T"
|
||
|
|
summary << "Only Crossovers"
|
||
|
|
elsif crossover.to_s == "F"
|
||
|
|
summary << "No Crossovers"
|
||
|
|
end
|
||
|
|
if %w(1 true).include?(self.single_chapter.to_s)
|
||
|
|
summary << "Single Chapter"
|
||
|
|
end
|
||
|
|
if @options[:language_id].present?
|
||
|
|
language = Language.find_by(short: @options[:language_id])
|
||
|
|
if language.present?
|
||
|
|
summary << "Language: <span lang=#{language.short}>#{language.name}</span>"
|
||
|
|
end
|
||
|
|
end
|
||
|
|
[:word_count, :hits, :kudos_count, :comments_count, :bookmarks_count, :revised_at].each do |countable|
|
||
|
|
if @options[countable].present?
|
||
|
|
summary << "#{countable.to_s.humanize.downcase}: #{@options[countable]}"
|
||
|
|
end
|
||
|
|
end
|
||
|
|
if @options[:sort_column].present?
|
||
|
|
# Use pretty name if available, otherwise fall back to plain column name
|
||
|
|
pretty_sort_name = name_for_sort_column(@options[:sort_column])
|
||
|
|
direction = if @options[:sort_direction].present?
|
||
|
|
@options[:sort_direction] == "asc" ? " ascending" : " descending"
|
||
|
|
else
|
||
|
|
""
|
||
|
|
end
|
||
|
|
summary << ("sort by: #{pretty_sort_name&.downcase || @options[:sort_column]}" + direction)
|
||
|
|
end
|
||
|
|
summary.join(" ")
|
||
|
|
end
|
||
|
|
|
||
|
|
def search_results
|
||
|
|
@searcher.search_results
|
||
|
|
end
|
||
|
|
|
||
|
|
###############
|
||
|
|
# SORTING
|
||
|
|
###############
|
||
|
|
|
||
|
|
SORT_OPTIONS = [
|
||
|
|
["Best Match", "_score"],
|
||
|
|
%w[Creator authors_to_sort_on],
|
||
|
|
%w[Title title_to_sort_on],
|
||
|
|
["Date Posted", "created_at"],
|
||
|
|
["Date Updated", "revised_at"],
|
||
|
|
["Word Count", "word_count"],
|
||
|
|
%w[Hits hits],
|
||
|
|
%w[Kudos kudos_count],
|
||
|
|
%w[Comments comments_count],
|
||
|
|
%w[Bookmarks bookmarks_count]
|
||
|
|
].freeze
|
||
|
|
|
||
|
|
def sort_columns
|
||
|
|
options[:sort_column] || default_sort_column
|
||
|
|
end
|
||
|
|
|
||
|
|
def sort_direction
|
||
|
|
options[:sort_direction] || default_sort_direction
|
||
|
|
end
|
||
|
|
|
||
|
|
def sort_options
|
||
|
|
options[:faceted] || options[:collected] ? SORT_OPTIONS[1..-1] : SORT_OPTIONS
|
||
|
|
end
|
||
|
|
|
||
|
|
def sort_values
|
||
|
|
sort_options.map{ |option| option.last }
|
||
|
|
end
|
||
|
|
|
||
|
|
# extract the pretty name
|
||
|
|
def name_for_sort_column(sort_column)
|
||
|
|
Hash[SORT_OPTIONS.map { |v| [v[1], v[0]] }][sort_column]
|
||
|
|
end
|
||
|
|
|
||
|
|
def default_sort_column
|
||
|
|
options[:faceted] || options[:collected] ? 'revised_at' : '_score'
|
||
|
|
end
|
||
|
|
|
||
|
|
def default_sort_direction
|
||
|
|
if %w[authors_to_sort_on title_to_sort_on].include?(sort_column)
|
||
|
|
'asc'
|
||
|
|
else
|
||
|
|
'desc'
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|