mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-12 11:37:39 -05:00
Fix search queries without a positive non-empty clause being allowed (#40196)
This commit is contained in:
@@ -20,6 +20,7 @@ class SearchQueryTransformer < Parslet::Transform
|
||||
@options = options
|
||||
|
||||
flags_from_clauses!
|
||||
validate_clauses!
|
||||
end
|
||||
|
||||
def request
|
||||
@@ -34,6 +35,11 @@ class SearchQueryTransformer < Parslet::Transform
|
||||
|
||||
private
|
||||
|
||||
def validate_clauses!
|
||||
# At least one clause should be a positive match unless searching within the library
|
||||
raise 'Empty query not supported' if @flags['in'] != 'library' && (must_clauses + filter_clauses).none? { |clause| clause.is_a?(TermClause) && clause.term.present? }
|
||||
end
|
||||
|
||||
def clauses_by_operator
|
||||
@clauses_by_operator ||= @clauses.compact.group_by(&:operator)
|
||||
end
|
||||
@@ -130,16 +136,9 @@ class SearchQueryTransformer < Parslet::Transform
|
||||
end
|
||||
end
|
||||
|
||||
class PhraseClause
|
||||
attr_reader :operator, :phrase
|
||||
|
||||
def initialize(operator, phrase)
|
||||
@operator = Operator.symbol(operator)
|
||||
@phrase = phrase
|
||||
end
|
||||
|
||||
class PhraseClause < TermClause
|
||||
def to_query
|
||||
{ match_phrase: { text: { query: @phrase } } }
|
||||
{ match_phrase: { text: { query: @term } } }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -18,13 +18,13 @@ RSpec.describe SearchQueryTransformer do
|
||||
['"12345678"', '12345678'],
|
||||
['"2024-10-31T23:47:20Z"', '2024-10-31T23:47:20Z'],
|
||||
].each do |value, parsed|
|
||||
context "with #{operator}:#{value}" do
|
||||
let(:query) { "#{operator}:#{value}" }
|
||||
context "with \"foo #{operator}:#{value}\"" do
|
||||
let(:query) { "foo #{operator}:#{value}" }
|
||||
|
||||
it 'transforms clauses' do
|
||||
ops = statement_operations.index_with { |_op| parsed }
|
||||
|
||||
expect(subject.send(:must_clauses)).to be_empty
|
||||
expect(subject.send(:must_clauses).map(&:term)).to contain_exactly('foo')
|
||||
expect(subject.send(:must_not_clauses)).to be_empty
|
||||
expect(subject.send(:filter_clauses).map(&:term)).to contain_exactly(**ops, time_zone: 'UTC')
|
||||
end
|
||||
@@ -40,6 +40,56 @@ RSpec.describe SearchQueryTransformer do
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is no positive clause' do
|
||||
context 'with "-hello"' do
|
||||
let(:query) { '-hello' }
|
||||
|
||||
it 'raises an exception' do
|
||||
expect { subject }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with "after:0000"' do
|
||||
let(:query) { 'after:0000' }
|
||||
|
||||
it 'raises an exception' do
|
||||
expect { subject }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with "before:9999"' do
|
||||
let(:query) { 'before:9999' }
|
||||
|
||||
it 'raises an exception' do
|
||||
expect { subject }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with "is:reply"' do
|
||||
let(:query) { 'is:reply' }
|
||||
|
||||
it 'raises an exception' do
|
||||
expect { subject }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with \'is:reply " "\'' do
|
||||
let(:query) { 'is:reply " "' }
|
||||
|
||||
it 'raises an exception' do
|
||||
expect { subject }.to raise_error(RuntimeError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with "in:library after:0000"' do
|
||||
let(:query) { 'in:library after:0000' }
|
||||
|
||||
it 'does not raise an exception' do
|
||||
expect { subject }.to_not raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with "hello world"' do
|
||||
let(:query) { 'hello world' }
|
||||
|
||||
@@ -94,17 +144,17 @@ RSpec.describe SearchQueryTransformer do
|
||||
let(:query) { '"hello world"' }
|
||||
|
||||
it 'transforms clauses' do
|
||||
expect(subject.send(:must_clauses).map(&:phrase)).to contain_exactly('hello world')
|
||||
expect(subject.send(:must_clauses).map(&:term)).to contain_exactly('hello world')
|
||||
expect(subject.send(:must_not_clauses)).to be_empty
|
||||
expect(subject.send(:filter_clauses)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'with \'is:"foo bar"\'' do
|
||||
let(:query) { 'is:"foo bar"' }
|
||||
context 'with \'foo is:"foo bar"\'' do
|
||||
let(:query) { 'foo is:"foo bar"' }
|
||||
|
||||
it 'transforms clauses' do
|
||||
expect(subject.send(:must_clauses)).to be_empty
|
||||
expect(subject.send(:must_clauses).map(&:term)).to contain_exactly('foo')
|
||||
expect(subject.send(:must_not_clauses)).to be_empty
|
||||
expect(subject.send(:filter_clauses).map(&:term)).to contain_exactly('foo bar')
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user