FEATURE: add `f` and `t` search shortcuts for first post / title

Previously with had `in:title` and `in:first` search shortcuts for
searching in first post or title only. They are a bit of handful to type.

This add 2 shortcuts (t and f) for searching titles of first posts.

This commit also cleans up all advanced filters, they were not properly
regex terminated allowing for weird clauses like `in:firstinator` acting
the same as `in:first`
This commit is contained in:
Sam 2019-02-25 10:55:24 +11:00
parent 2d031a1beb
commit 0a357299b7
2 changed files with 41 additions and 29 deletions

View File

@ -253,43 +253,43 @@ class Search
@advanced_filters @advanced_filters
end end
advanced_filter(/status:open/) do |posts| advanced_filter(/^status:open$/) do |posts|
posts.where('NOT topics.closed AND NOT topics.archived') posts.where('NOT topics.closed AND NOT topics.archived')
end end
advanced_filter(/status:closed/) do |posts| advanced_filter(/^status:closed$/) do |posts|
posts.where('topics.closed') posts.where('topics.closed')
end end
advanced_filter(/status:archived/) do |posts| advanced_filter(/^status:archived$/) do |posts|
posts.where('topics.archived') posts.where('topics.archived')
end end
advanced_filter(/status:noreplies/) do |posts| advanced_filter(/^status:noreplies$/) do |posts|
posts.where("topics.posts_count = 1") posts.where("topics.posts_count = 1")
end end
advanced_filter(/status:single_user/) do |posts| advanced_filter(/^status:single_user$/) do |posts|
posts.where("topics.participant_count = 1") posts.where("topics.participant_count = 1")
end end
advanced_filter(/posts_count:(\d+)/) do |posts, match| advanced_filter(/^posts_count:(\d+)$/) do |posts, match|
posts.where("topics.posts_count = ?", match.to_i) posts.where("topics.posts_count = ?", match.to_i)
end end
advanced_filter(/min_post_count:(\d+)/) do |posts, match| advanced_filter(/^min_post_count:(\d+)$/) do |posts, match|
posts.where("topics.posts_count >= ?", match.to_i) posts.where("topics.posts_count >= ?", match.to_i)
end end
advanced_filter(/in:first/) do |posts| advanced_filter(/^in:first|^f$/) do |posts|
posts.where("posts.post_number = 1") posts.where("posts.post_number = 1")
end end
advanced_filter(/in:pinned/) do |posts| advanced_filter(/^in:pinned$/) do |posts|
posts.where("topics.pinned_at IS NOT NULL") posts.where("topics.pinned_at IS NOT NULL")
end end
advanced_filter(/in:unpinned/) do |posts| advanced_filter(/^in:unpinned$/) do |posts|
if @guardian.user if @guardian.user
posts.where("topics.pinned_at IS NOT NULL AND topics.id IN ( posts.where("topics.pinned_at IS NOT NULL AND topics.id IN (
SELECT topic_id FROM topic_users WHERE user_id = ? AND cleared_pinned_at IS NOT NULL SELECT topic_id FROM topic_users WHERE user_id = ? AND cleared_pinned_at IS NOT NULL
@ -297,11 +297,11 @@ class Search
end end
end end
advanced_filter(/in:wiki/) do |posts, match| advanced_filter(/^in:wiki$/) do |posts, match|
posts.where(wiki: true) posts.where(wiki: true)
end end
advanced_filter(/badge:(.*)/) do |posts, match| advanced_filter(/^badge:(.*)$/) do |posts, match|
badge_id = Badge.where('name ilike ? OR id = ?', match, match.to_i).pluck(:id).first badge_id = Badge.where('name ilike ? OR id = ?', match, match.to_i).pluck(:id).first
if badge_id if badge_id
posts.where('posts.user_id IN (SELECT ub.user_id FROM user_badges ub WHERE ub.badge_id = ?)', badge_id) posts.where('posts.user_id IN (SELECT ub.user_id FROM user_badges ub WHERE ub.badge_id = ?)', badge_id)
@ -310,7 +310,7 @@ class Search
end end
end end
advanced_filter(/in:(likes|bookmarks)/) do |posts, match| advanced_filter(/^in:(likes|bookmarks)$/) do |posts, match|
if @guardian.user if @guardian.user
post_action_type = PostActionType.types[:like] if match == "likes" post_action_type = PostActionType.types[:like] if match == "likes"
post_action_type = PostActionType.types[:bookmark] if match == "bookmarks" post_action_type = PostActionType.types[:bookmark] if match == "bookmarks"
@ -324,11 +324,11 @@ class Search
end end
end end
advanced_filter(/in:posted/) do |posts| advanced_filter(/^in:posted$/) do |posts|
posts.where("posts.user_id = #{@guardian.user.id}") if @guardian.user posts.where("posts.user_id = #{@guardian.user.id}") if @guardian.user
end end
advanced_filter(/in:(watching|tracking)/) do |posts, match| advanced_filter(/^in:(watching|tracking)$/) do |posts, match|
if @guardian.user if @guardian.user
level = TopicUser.notification_levels[match.to_sym] level = TopicUser.notification_levels[match.to_sym]
posts.where("posts.topic_id IN ( posts.where("posts.topic_id IN (
@ -340,7 +340,7 @@ class Search
end end
end end
advanced_filter(/in:seen/) do |posts| advanced_filter(/^in:seen$/) do |posts|
if @guardian.user if @guardian.user
posts posts
.joins("INNER JOIN post_timings ON .joins("INNER JOIN post_timings ON
@ -351,7 +351,7 @@ class Search
end end
end end
advanced_filter(/in:unseen/) do |posts| advanced_filter(/^in:unseen$/) do |posts|
if @guardian.user if @guardian.user
posts posts
.joins("LEFT JOIN post_timings ON .joins("LEFT JOIN post_timings ON
@ -363,11 +363,11 @@ class Search
end end
end end
advanced_filter(/with:images/) do |posts| advanced_filter(/^with:images$/) do |posts|
posts.where("posts.image_url IS NOT NULL") posts.where("posts.image_url IS NOT NULL")
end end
advanced_filter(/category:(.+)/) do |posts, match| advanced_filter(/^category:(.+)$/) do |posts, match|
exact = false exact = false
if match[0] == "=" if match[0] == "="
@ -390,7 +390,7 @@ class Search
end end
end end
advanced_filter(/^\#([\p{L}0-9\-:=]+)/) do |posts, match| advanced_filter(/^\#([\p{L}0-9\-:=]+)$/) do |posts, match|
exact = true exact = true
@ -443,7 +443,7 @@ class Search
end end
end end
advanced_filter(/group:(.+)/) do |posts, match| advanced_filter(/^group:(.+)$/) do |posts, match|
group_id = Group.where('name ilike ? OR (id = ? AND id > 0)', match, match.to_i).pluck(:id).first group_id = Group.where('name ilike ? OR (id = ? AND id > 0)', match, match.to_i).pluck(:id).first
if group_id if group_id
posts.where("posts.user_id IN (select gu.user_id from group_users gu where gu.group_id = ?)", group_id) posts.where("posts.user_id IN (select gu.user_id from group_users gu where gu.group_id = ?)", group_id)
@ -452,7 +452,7 @@ class Search
end end
end end
advanced_filter(/user:(.+)/) do |posts, match| advanced_filter(/^user:(.+)$/) do |posts, match|
user_id = User.where(staged: false).where('username_lower = ? OR id = ?', match.downcase, match.to_i).pluck(:id).first user_id = User.where(staged: false).where('username_lower = ? OR id = ?', match.downcase, match.to_i).pluck(:id).first
if user_id if user_id
posts.where("posts.user_id = #{user_id}") posts.where("posts.user_id = #{user_id}")
@ -461,7 +461,7 @@ class Search
end end
end end
advanced_filter(/^\@([a-zA-Z0-9_\-.]+)/) do |posts, match| advanced_filter(/^\@([a-zA-Z0-9_\-.]+)$/) do |posts, match|
user_id = User.where(staged: false).where(username_lower: match.downcase).pluck(:id).first user_id = User.where(staged: false).where(username_lower: match.downcase).pluck(:id).first
if user_id if user_id
posts.where("posts.user_id = #{user_id}") posts.where("posts.user_id = #{user_id}")
@ -470,7 +470,7 @@ class Search
end end
end end
advanced_filter(/before:(.*)/) do |posts, match| advanced_filter(/^before:(.*)$/) do |posts, match|
if date = Search.word_to_date(match) if date = Search.word_to_date(match)
posts.where("posts.created_at < ?", date) posts.where("posts.created_at < ?", date)
else else
@ -478,7 +478,7 @@ class Search
end end
end end
advanced_filter(/after:(.*)/) do |posts, match| advanced_filter(/^after:(.*)$/) do |posts, match|
if date = Search.word_to_date(match) if date = Search.word_to_date(match)
posts.where("posts.created_at > ?", date) posts.where("posts.created_at > ?", date)
else else
@ -486,15 +486,15 @@ class Search
end end
end end
advanced_filter(/^tags?:([\p{L}0-9,\-_+]+)/) do |posts, match| advanced_filter(/^tags?:([\p{L}0-9,\-_+]+)$/) do |posts, match|
search_tags(posts, match, positive: true) search_tags(posts, match, positive: true)
end end
advanced_filter(/\-tags?:([\p{L}0-9,\-_+]+)/) do |posts, match| advanced_filter(/^\-tags?:([\p{L}0-9,\-_+]+)$/) do |posts, match|
search_tags(posts, match, positive: false) search_tags(posts, match, positive: false)
end end
advanced_filter(/filetypes?:([a-zA-Z0-9,\-_]+)/) do |posts, match| advanced_filter(/^filetypes?:([a-zA-Z0-9,\-_]+)$/) do |posts, match|
file_extensions = match.split(",").map(&:downcase) file_extensions = match.split(",").map(&:downcase)
posts.where("posts.id IN ( posts.where("posts.id IN (
SELECT post_id SELECT post_id
@ -558,7 +558,7 @@ class Search
elsif word == 'order:latest_topic' elsif word == 'order:latest_topic'
@order = :latest_topic @order = :latest_topic
nil nil
elsif word == 'in:title' elsif word == 'in:title' || word == 't'
@in_title = true @in_title = true
nil nil
elsif word =~ /topic:(\d+)/ elsif word =~ /topic:(\d+)/

View File

@ -701,8 +701,14 @@ describe Search do
expect(Search.execute('test after:jan').posts.length).to eq(1) expect(Search.execute('test after:jan').posts.length).to eq(1)
expect(Search.execute('test in:first').posts.length).to eq(1) expect(Search.execute('test in:first').posts.length).to eq(1)
expect(Search.execute('boom').posts.length).to eq(1) expect(Search.execute('boom').posts.length).to eq(1)
expect(Search.execute('boom in:first').posts.length).to eq(0) expect(Search.execute('boom in:first').posts.length).to eq(0)
expect(Search.execute('boom f').posts.length).to eq(0)
expect(Search.execute('123 in:first').posts.length).to eq(1)
expect(Search.execute('123 f').posts.length).to eq(1)
expect(Search.execute('user:nobody').posts.length).to eq(0) expect(Search.execute('user:nobody').posts.length).to eq(0)
expect(Search.execute("user:#{_post.user.username}").posts.length).to eq(1) expect(Search.execute("user:#{_post.user.username}").posts.length).to eq(1)
@ -1050,8 +1056,14 @@ describe Search do
results = Search.execute('title in:title') results = Search.execute('title in:title')
expect(results.posts.length).to eq(1) expect(results.posts.length).to eq(1)
results = Search.execute('title t')
expect(results.posts.length).to eq(1)
results = Search.execute('first in:title') results = Search.execute('first in:title')
expect(results.posts.length).to eq(0) expect(results.posts.length).to eq(0)
results = Search.execute('first t')
expect(results.posts.length).to eq(0)
end end
it 'works irrespective of the order' do it 'works irrespective of the order' do