diff --git a/app/lib/search_query_transformer.rb b/app/lib/search_query_transformer.rb index 9417305ba2..d67ba8d936 100644 --- a/app/lib/search_query_transformer.rb +++ b/app/lib/search_query_transformer.rb @@ -242,17 +242,20 @@ class SearchQueryTransformer < Parslet::Transform class TermClause attr_reader :operator, :term - def initialize(operator, term) + def initialize(operator, term, current_account: nil) @operator = Operator.symbol(operator) @term = term + @account = current_account end def to_query if @term.start_with?('#') { match: { tags: { query: @term, operator: 'and' } } } - else + elsif @account&.user&.setting_reverse_search_quote # Memo for checking when manually merge # { multi_match: { type: 'most_fields', query: @term, fields: ['text', 'text.stemmed'], operator: 'and' } } + { match_phrase: { text: { query: @term } } } + else { multi_match: { type: 'most_fields', query: @term, fields: ['text', 'text.stemmed'], operator: 'and' } } end end @@ -261,15 +264,20 @@ class SearchQueryTransformer < Parslet::Transform class PhraseClause attr_reader :operator, :phrase - def initialize(operator, phrase) + def initialize(operator, phrase, current_account: nil) @operator = Operator.symbol(operator) @phrase = phrase + @account = current_account end def to_query # Memo for checking when manually merge # { match_phrase: { text: { query: @phrase } } } - { match_phrase: { text: { query: @phrase } } } + if @account&.user&.setting_reverse_search_quote + { multi_match: { type: 'most_fields', query: @phrase, fields: ['text', 'text.stemmed'], operator: 'and' } } + else + { match_phrase: { text: { query: @phrase } } } + end end end @@ -411,11 +419,11 @@ class SearchQueryTransformer < Parslet::Transform if clause[:prefix] && SUPPORTED_PREFIXES.include?(prefix) PrefixClause.new(prefix, operator, term, current_account: current_account) elsif clause[:prefix] - TermClause.new(operator, "#{prefix} #{term}") + TermClause.new(operator, "#{prefix} #{term}", current_account: current_account) elsif clause[:term] - TermClause.new(operator, term) + TermClause.new(operator, term, current_account: current_account) elsif clause[:phrase] - PhraseClause.new(operator, term) + PhraseClause.new(operator, term, current_account: current_account) else raise "Unexpected clause type: #{clause}" end diff --git a/app/models/concerns/user/has_settings.rb b/app/models/concerns/user/has_settings.rb index 79072a7f30..bfa2388cf8 100644 --- a/app/models/concerns/user/has_settings.rb +++ b/app/models/concerns/user/has_settings.rb @@ -243,6 +243,10 @@ module User::HasSettings settings['use_public_index'] end + def setting_reverse_search_quote + settings['reverse_search_quote'] + end + def setting_disallow_unlisted_public_searchability settings['disallow_unlisted_public_searchability'] end diff --git a/app/models/user_settings.rb b/app/models/user_settings.rb index ba5883d03f..9a17d368ce 100644 --- a/app/models/user_settings.rb +++ b/app/models/user_settings.rb @@ -26,6 +26,7 @@ class UserSettings setting :default_searchability, default: :direct, in: %w(public private direct limited public_unlisted) setting :default_searchability_of_search, default: :public, in: %w(public private direct limited) setting :use_public_index, default: true + setting :reverse_search_quote, default: false setting :disallow_unlisted_public_searchability, default: false setting :public_post_to_unlisted, default: false setting :reject_public_unlisted_subscription, default: false diff --git a/app/views/settings/preferences/reaching/show.html.haml b/app/views/settings/preferences/reaching/show.html.haml index c08e79daff..a2053da7cc 100644 --- a/app/views/settings/preferences/reaching/show.html.haml +++ b/app/views/settings/preferences/reaching/show.html.haml @@ -72,6 +72,8 @@ label_method: ->(searchability) { safe_join([I18n.t("statuses.searchabilities.#{searchability}"), I18n.t("statuses.searchabilities.#{searchability}_search_long")], ' - ') }, required: false, wrapper: :with_label + .fields-group + = ff.input :reverse_search_quote, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_reverse_search_quote'), hint: I18n.t('simple_form.hints.defaults.setting_reverse_search_quote') .fields-group = ff.input :use_public_index, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_use_public_index') diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index c0dc68c385..6d20f856b3 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -72,6 +72,7 @@ en: setting_dtl_menu: Show DTL menu on web setting_emoji_reaction_policy: Even with this setting, users on other servers are free to put their stamp on the post and share it within the same server. If you simply want to remove the stamp from your own screen, you can disable it from the appearance settings setting_enable_emoji_reaction: If turn off, other users still can react your posts + setting_reverse_search_quote: Double-quotes will result in a search with a wider range of notation, which is the opposite of Mastodon's default behavior. setting_single_ref_to_quote: If this server does not have target post, target server maybe cannot read your quote setting_use_blurhash: Gradients are based on the colors of the hidden visuals but obfuscate any details setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed @@ -283,6 +284,7 @@ en: setting_reduce_motion: Reduce motion in animations setting_reject_public_unlisted_subscription: Reject sending public unlisted visibility/non-public searchability posts to Misskey, Calckey setting_reject_unlisted_subscription: Reject sending unlisted visibility/non-public searchability posts to Misskey, Calckey + setting_reverse_search_quote: Perform word-by-word search when search keywords are not enclosed in double quotes setting_send_without_domain_blocks: Send your post to all server with administrator set as rejecting-post-server for protect you [DEPRECATED] setting_show_application: Disclose application used to send posts setting_show_emoji_reaction_on_timeline: Show all stamps on timeline diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index ffefa6b347..9d3ea08a21 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -81,6 +81,7 @@ ja: setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします setting_public_post_to_unlisted: 未対応のサードパーティアプリからもローカル公開で投稿できますが、公開投稿はWeb以外できなくなります setting_reject_unlisted_subscription: Misskeyやそのフォークは、フォローしていないアカウントの「非収載」投稿を **購読・検索** することができます。これはkmyblueの挙動と異なります。そのようなサーバーに、指定した公開範囲の投稿を「フォロワーのみ」として配送します。ただし構造上、完璧な対応は困難でたまに非収載として配信されること、ご理解ください + setting_reverse_search_quote: 検索ワードをダブルクオートで囲って検索した場合、表記ゆれ多めの検索結果になります。Mastodon標準とは逆の挙動となります。 setting_show_application: 投稿するのに使用したアプリが投稿の詳細ビューに表示されるようになります setting_single_ref_to_quote: 当サーバーがまだ対象投稿を取り込んでいない場合、引用が相手に正常に認識されない場合があります setting_stop_emoji_reaction_streaming: 通信容量の節約に役立ちます @@ -294,6 +295,7 @@ ja: setting_reduce_motion: アニメーションの動きを減らす setting_reject_public_unlisted_subscription: Misskey系サーバーに「ローカル公開」かつ検索許可「誰でも以外」の投稿を「フォロワーのみ」に変換して配送する setting_reject_unlisted_subscription: Misskey系サーバーに「非収載」かつ検索許可「誰でも以外」の投稿を「フォロワーのみ」に変換して配送する + setting_reverse_search_quote: ダブルクオートで囲まず検索した時、単語単位で検索する setting_send_without_domain_blocks: 管理人の設定した配送停止設定を拒否する (非推奨) setting_show_application: 送信したアプリを開示する setting_show_emoji_reaction_on_timeline: タイムライン上に他の人のつけたスタンプを表示する diff --git a/spec/search/services/statuses_search_service_spec.rb b/spec/search/services/statuses_search_service_spec.rb index 383fa86eec..a18f767f94 100644 --- a/spec/search/services/statuses_search_service_spec.rb +++ b/spec/search/services/statuses_search_service_spec.rb @@ -289,5 +289,15 @@ describe StatusesSearchService do it_behaves_like 'does not hit status', 'when search with following', 'in:following りんご' end end + + context 'when reverse_search_quote is enabled' do + before do + alice.user.update!(settings: { reverse_search_quote: true }) + end + + it_behaves_like 'does not hit status', 'when search with letter in word', 'ご' + it_behaves_like 'hit status', 'when double quote search with letter in word', '"ご"' + it_behaves_like 'hit status', 'when search with word', 'りんご' + end end end