fix: fix author links, refactor search scope junk

This commit is contained in:
Neetpone 2024-04-06 21:34:20 -04:00
parent 04a814b71b
commit 390b7ac486
8 changed files with 86 additions and 70 deletions

View file

@ -56,4 +56,8 @@ Layout/CaseIndentation:
IndentOneStep: true
Style/NumericPredicate:
Enabled: false
# I've always been an "unnecessary this->" guy myself.
Style/RedundantSelf:
Enabled: false

10
Gemfile
View file

@ -11,16 +11,16 @@ gem 'sprockets-rails'
gem 'pg', '~> 1.1'
gem 'redis'
# Views
gem 'kaminari' # Must be included before ElasticSearch
gem 'redcarpet'
gem 'slim-rails'
# Search
gem 'elasticsearch-model'
gem 'fancy_searchable', github: 'Twibooru/fancy_searchable', ref: '40687c9'
gem 'model-msearch'
# Views
gem 'kaminari'
gem 'redcarpet'
gem 'slim-rails'
# Programs
gem 'puma', '~> 5.0'
gem 'sidekiq'

View file

@ -82,7 +82,6 @@ GEM
rake (>= 10.4, < 14.0)
ast (2.4.2)
base64 (0.2.0)
bcrypt (3.1.20)
bindex (0.8.1)
builder (3.2.4)
bullet (7.1.6)
@ -301,7 +300,6 @@ PLATFORMS
DEPENDENCIES
annotate
bcrypt
bullet
capybara
debug

View file

@ -1,6 +1,9 @@
# frozen_string_literal: true
class AuthorsController < ApplicationController
def show
@author = Author.find(params[:id])
author = Author.select(:name).find(params[:id])
scope = SearchScope.new(nil, { author: author.name })
redirect_to "/search?scope=#{scope.scope_key}"
end
end

View file

@ -11,11 +11,20 @@ class SearchController < ApplicationController
end
def search
unless setup_scope
return
# unless params[:scope]
# return redirect_to root_path
# end
@scope = SearchScope.new(params)
# The scope is valid if was successfully used to load the existing search params
unless @scope.scope_loaded
return redirect_to "/search?scope=#{@scope.scope_key}"
end
using_random = @search_params['luck'].present?
@search_params = @scope.search_params
using_random = @search_params[:luck].present?
# This was mainly written this way to match the way FiMFetch's query interface looks, without using JS.
# I should do a Derpibooru-esque textual search system sometime.
@ -23,8 +32,8 @@ class SearchController < ApplicationController
per_page: @per_page,
page: @page_num
) do |s|
s.add_query(match: { title: { query: @search_params['q'], operator: :and } }) if @search_params['q'].present?
s.add_query(match: { author: { query: @search_params['author'], operator: :and } }) if @search_params['author'].present?
s.add_query(match: { title: { query: @search_params[:q], operator: :and } }) if @search_params[:q].present?
s.add_query(match: { author: { query: @search_params[:author], operator: :and } }) if @search_params[:author].present?
# tags -> match any of the included tags, exclude any of the excluded tags
tag_musts, tag_must_nots = parse_tag_queries
@ -42,13 +51,13 @@ class SearchController < ApplicationController
# ratings -> match stories with any of them
s.add_filter(bool: {
should: @search_params['ratings'].keys.map { |k| { term: { content_rating: k } } }
}) if @search_params['ratings'].present?
should: @search_params[:ratings].keys.map { |k| { term: { content_rating: k } } }
}) if @search_params[:ratings].present?
# completeness -> match stories with any of them
s.add_filter(bool: {
should: @search_params['state'].keys.map { |k| { term: { completion_status: k } } }
}) if @search_params['state'].present?
should: @search_params[:state].keys.map { |k| { term: { completion_status: k } } }
}) if @search_params[:state].present?
# sort direction
if using_random
@ -75,7 +84,7 @@ class SearchController < ApplicationController
# returns: [included tags, excluded tags]
def parse_tag_queries
tag_searches = "#{@search_params['tags']},#{@search_params['characters']}".split(',').reject(&:blank?)
tag_searches = "#{@search_params[:tas]},#{@search_params[:characters]}".split(',').reject(&:blank?)
[
tag_searches.reject { |t| t[0] == '-' },
@ -85,8 +94,8 @@ class SearchController < ApplicationController
end
def parse_sort
sf = ALLOWED_SORT_FIELDS.detect { |f| @search_params['sf'] == f.to_s } || :date_updated
sd = ALLOWED_SORT_DIRS.detect { |d| @search_params['sd'] == d.to_s } || :desc
sf = ALLOWED_SORT_FIELDS.detect { |f| @search_params[:sf] == f.to_s } || :date_updated
sd = ALLOWED_SORT_DIRS.detect { |d| @search_params[:sd] == d.to_s } || :desc
# we need to sort on the keyword versions of text fields, to avoid using fielddata.
sf = case sf
@ -102,40 +111,4 @@ class SearchController < ApplicationController
{sf => sd}
end
# FIXME: This is some of the worst Ruby code I have ever written.
def setup_scope
@scope_key = Random.hex(16)
scope_valid = false
# scope passed, try to look it up in redis and use the search params from it
if params[:scope].present?
result = $redis.get("search_scope/#{params[:scope]}")
if result.present?
@search_params = JSON.parse(result)
@scope_key = params[:scope]
scope_valid = true
else
redirect_to '/'
return false
end
else
@search_params = params
end
# you can't JSON.dump a Parameters
if @search_params.is_a? ActionController::Parameters
@search_params = @search_params.permit!.to_h
end
$redis.setex("search_scope/#{@scope_key}", 3600, JSON.dump(@search_params))
# if the scope was invalid (no key passed, or invalid key passed), redirect to the results page
# with the new key we just generated for the params we had.
unless scope_valid
redirect_to "/search?scope=#{@scope_key}"
return false
end
true
end
end

38
app/lib/search_scope.rb Normal file
View file

@ -0,0 +1,38 @@
# frozen_string_literal: true
class SearchScope
attr_reader :search_params, :scope_key, :scope_loaded
def initialize(params, search_params = nil)
@scope_key = SecureRandom.hex 16
@scope_loaded = false
if search_params
@search_params = search_params
self.persist
elsif params
self.load_from_params(params)
end
end
private
def load_from_params(params)
if params[:scope].present?
result = $redis.get("search_scope/#{params[:scope]}")
if result.present?
@search_params = JSON.parse(result, symbolize_names: true)
@scope_key = params[:scope]
@scope_loaded = true
self.persist # refresh the expiry
end
else
@search_params = params.permit!.to_h.symbolize_keys
self.persist
end
end
def persist
# Nice long expiry so nobody's search disappears if they don't touch it for awhile.
$redis.setex("search_scope/#{@scope_key}", 1.day.in_seconds, JSON.dump(@search_params))
end
end

View file

@ -9,28 +9,28 @@ div.search-adv
b Rating
br
= label_tag "ratings_everyone"
= check_box_tag "ratings[everyone]", 1, @search_params.dig('ratings', 'everyone').present?
= check_box_tag "ratings[everyone]", 1, @search_params.dig(:ratings, 'everyone').present?
| Everyone
= label_tag "ratings_teen"
= check_box_tag "ratings[teen]", 1, @search_params.dig('ratings', 'teen').present?
= check_box_tag "ratings[teen]", 1, @search_params.dig(:ratings, 'teen').present?
| Teen
= label_tag "ratings_mature"
= check_box_tag "ratings[mature]", 1, @search_params.dig('ratings', 'mature').present?
= check_box_tag "ratings[mature]", 1, @search_params.dig(:ratings, 'mature').present?
| Mature
.opts
b Story State
br
= label_tag "state_complete"
= check_box_tag "state[complete]", 1, @search_params.dig('state', 'complete').present?
= check_box_tag "state[complete]", 1, @search_params.dig(:state, 'complete').present?
| Complete
= label_tag "state_incomplete"
= check_box_tag "state[incomplete]", 1, @search_params.dig('state', 'incomplete').present?
= check_box_tag "state[incomplete]", 1, @search_params.dig(:state, 'incomplete').present?
| Incomplete
= label_tag "state_hiatus"
= check_box_tag "state[hiatus]", 1, @search_params.dig('state', 'hiatus').present?
= check_box_tag "state[hiatus]", 1, @search_params.dig(:state, 'hiatus').present?
| On Hiatus
= label_tag "state_cancelled"
= check_box_tag "state[cancelled]", 1, @search_params.dig('state', 'cancelled').present?
= check_box_tag "state[cancelled]", 1, @search_params.dig(:state, 'cancelled').present?
| Cancelled
/.opts
b Story Age
@ -73,7 +73,7 @@ div.search-adv
.opts
b Author:
br
= text_field_tag :author, @search_params['author']
= text_field_tag :author, @search_params[:author]
/.cols
.opts
b FiMFiction Rating:
@ -104,7 +104,7 @@ div.search-adv
br
.js-tag-editor
.selected-tags
= text_field_tag :characters, @search_params['characters']
= text_field_tag :characters, @search_params[:characters]
= select_tag :fancy_tags, options_for_select(@character_tags)
.cols
.opts
@ -112,15 +112,15 @@ div.search-adv
br
.js-tag-editor
.selected-tags
= text_field_tag :tags, @search_params['tags']
= text_field_tag :tags, @search_params[:tags]
= select_tag :fancy_characters, options_for_select(@other_tags)
.cols
.opts
b Sort By
br
=> select_tag :sf, options_for_select({'Query Relevance' => 'rel', 'Title' => 'title', 'Author' => 'author', \
'Publish Date' => 'date_published', 'Updated Date' => 'date_updated', 'Word Count' => 'num_words'}, @search_params['sf'])
= select_tag :sd, options_for_select({'High to Low' => 'desc', 'Low to High' => 'asc'}, @search_params['sd'])
'Publish Date' => 'date_published', 'Updated Date' => 'date_updated', 'Word Count' => 'num_words'}, @search_params[:sf])
= select_tag :sd, options_for_select({'High to Low' => 'desc', 'Low to High' => 'asc'}, @search_params[:sd])
- if show_button
.buttons
= submit_tag 'Go Fetch!', name: 'search'

View file

@ -5,7 +5,7 @@
a.logo href="/"
= image_tag '/img/logo_small.png'
.searchbox
= search_field_tag 'q', @search_params['q'], placeholder: 'Search story titles...'
= search_field_tag :q, @search_params[:q], placeholder: 'Search story titles...'
= render partial: 'advanced', locals: { show_button: true }
- @records.each do |rec|
@ -57,6 +57,6 @@
' Last Update
span= rec.date_updated
.searchnav
= paginate(@records, params: { scope: @scope_key })
= paginate(@records, params: { scope: @scope.scope_key })
br
span.searchtime Found #{@search.total_count} results.