mirror of
https://github.com/Neetpone/foalfetch.git
synced 2025-03-11 14:10:07 +01:00
fix: fix author links, refactor search scope junk
This commit is contained in:
parent
04a814b71b
commit
390b7ac486
8 changed files with 86 additions and 70 deletions
|
@ -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
10
Gemfile
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
38
app/lib/search_scope.rb
Normal 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
|
|
@ -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'
|
|
@ -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.
|
Loading…
Add table
Reference in a new issue