From 93a73ce9db0fe415966bafb8bee78558609f9790 Mon Sep 17 00:00:00 2001 From: Skye Date: Tue, 27 Dec 2022 16:52:26 +0900 Subject: [PATCH] Extended Search https://github.com/VyrCossont/mastodon/pull/2 --- .env.production.sample | 8 ++++++- app/chewy/statuses_index.rb | 1 + app/lib/activitypub/activity/create.rb | 2 ++ app/lib/importer/statuses_index_importer.rb | 22 +++++++++++++++++-- app/models/status.rb | 1 + .../activitypub/process_account_service.rb | 2 ++ .../process_status_update_service.rb | 2 ++ app/services/search_service.rb | 9 +++++++- config/initializers/search_scope.rb | 12 ++++++++++ 9 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 config/initializers/search_scope.rb diff --git a/.env.production.sample b/.env.production.sample index 7bcce0f7e5..63ff584dba 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -238,7 +238,7 @@ SMTP_FROM_ADDRESS=notifications@example.com # SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.16.840.1.113730.3.1.241" # SAML_ATTRIBUTES_STATEMENTS_FIRST_NAME="urn:oid:2.5.4.42" # SAML_ATTRIBUTES_STATEMENTS_LAST_NAME="urn:oid:2.5.4.4" -# SAML_UID_ATTRIBUTE="urn:oid:0.9.2342.19200300.100.1.1" +# SAML_UID_ATTRIBUTE="urn:oid:0.9.2342.19200300.100.1.1" # SAML_ATTRIBUTES_STATEMENTS_VERIFIED= # SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL= @@ -283,6 +283,12 @@ MAX_POLL_OPTION_CHARS=100 # Customize the number of hashtags shown in 'Explore' # MAX_TRENDING_TAGS=10 +# Scope of full-text searches: +# - public: search any status with public visibility +# - public_or_unlisted: search any status with public or unlisted visibility +# - classic: searches only a user's own statuses, favs, bookmarks, and mentions +# SEARCH_SCOPE=public + # Maximum custom emoji file sizes # If undefined or smaller than MAX_EMOJI_SIZE, the value # of MAX_EMOJI_SIZE will be used for MAX_REMOTE_EMOJI_SIZE diff --git a/app/chewy/statuses_index.rb b/app/chewy/statuses_index.rb index 6dd4fb18b0..d779a226a2 100644 --- a/app/chewy/statuses_index.rb +++ b/app/chewy/statuses_index.rb @@ -65,6 +65,7 @@ class StatusesIndex < Chewy::Index root date_detection: false do field :id, type: 'long' field :account_id, type: 'long' + field :visibility, type: 'keyword' field :text, type: 'text', value: ->(status) { status.searchable_text } do field :stemmed, type: 'text', analyzer: 'content' diff --git a/app/lib/activitypub/activity/create.rb b/app/lib/activitypub/activity/create.rb index a0414f9cb8..8576716c24 100644 --- a/app/lib/activitypub/activity/create.rb +++ b/app/lib/activitypub/activity/create.rb @@ -85,6 +85,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity attach_tags(@status) end + StatusesIndex.import! @status + resolve_thread(@status) fetch_replies(@status) distribute diff --git a/app/lib/importer/statuses_index_importer.rb b/app/lib/importer/statuses_index_importer.rb index 5b5153d5c8..795bb057c5 100644 --- a/app/lib/importer/statuses_index_importer.rb +++ b/app/lib/importer/statuses_index_importer.rb @@ -25,7 +25,9 @@ class Importer::StatusesIndexImporter < Importer::BaseImporter # on the results of the filter, so this filtering happens here instead bulk.map! do |entry| new_entry = begin - if entry[:index] && entry.dig(:index, :data, 'searchable_by').blank? + if entry[:index] && + entry.dig(:index, :data, 'searchable_by').blank? && + Rails.configuration.x.search_scope == :classic { delete: entry[:index].except(:data) } else entry @@ -58,13 +60,21 @@ class Importer::StatusesIndexImporter < Importer::BaseImporter end def scopes - [ + classic_scopes = [ local_statuses_scope, local_mentions_scope, local_favourites_scope, local_votes_scope, local_bookmarks_scope, ] + case Rails.configuration.x.search_scope + when :public + classic_scopes + [public_scope] + when :public_or_unlisted + classic_scopes + [public_or_unlisted_scope] + else + classic_scopes + end end def local_mentions_scope @@ -86,4 +96,12 @@ class Importer::StatusesIndexImporter < Importer::BaseImporter def local_statuses_scope Status.local.select('"statuses"."id", COALESCE("statuses"."reblog_of_id", "statuses"."id") AS status_id') end + + def public_scope + Status.with_public_visibility.select('"statuses"."id", "statuses"."id" AS status_id') + end + + def public_or_unlisted_scope + Status.with_public_or_unlisted_visibility.select('"statuses"."id", "statuses"."id" AS status_id') + end end diff --git a/app/models/status.rb b/app/models/status.rb index 18c99f1bec..af71ab363a 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -103,6 +103,7 @@ class Status < ApplicationRecord scope :without_replies, -> { where('statuses.reply = FALSE OR statuses.in_reply_to_account_id = statuses.account_id') } scope :without_reblogs, -> { where('statuses.reblog_of_id IS NULL') } scope :with_public_visibility, -> { where(visibility: :public) } + scope :with_public_or_unlisted_visibility, -> { where(visibility: [:public, :unlisted]) } scope :tagged_with, ->(tag_ids) { joins(:statuses_tags).where(statuses_tags: { tag_id: tag_ids }) } scope :excluding_silenced_accounts, -> { left_outer_joins(:account).where(accounts: { silenced_at: nil }) } scope :including_silenced_accounts, -> { left_outer_joins(:account).where.not(accounts: { silenced_at: nil }) } diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb index 2da9096c73..3ba20a5f39 100644 --- a/app/services/activitypub/process_account_service.rb +++ b/app/services/activitypub/process_account_service.rb @@ -90,6 +90,8 @@ class ActivityPub::ProcessAccountService < BaseService set_fetchable_attributes! unless @options[:only_key] || @account.suspended? @account.save_with_optional_media! + + AccountsIndex.import! @account end def set_immediate_protocol_attributes! diff --git a/app/services/activitypub/process_status_update_service.rb b/app/services/activitypub/process_status_update_service.rb index 11b38ab92b..72d53bb008 100644 --- a/app/services/activitypub/process_status_update_service.rb +++ b/app/services/activitypub/process_status_update_service.rb @@ -54,6 +54,8 @@ class ActivityPub::ProcessStatusUpdateService < BaseService broadcast_updates! end + StatusesIndex.import! @status + forward_activity! if significant_changes? && @status_parser.edited_at > last_edit_date end diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 1a76cbb388..a9ed121529 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -35,7 +35,14 @@ class SearchService < BaseService end def perform_statuses_search! - definition = parsed_query.apply(StatusesIndex.filter(term: { searchable_by: @account.id })) + statuses_index = StatusesIndex.filter(term: { searchable_by: @account.id }) + case Rails.configuration.x.search_scope + when :public + statuses_index = statuses_index.filter.or(term: { visibility: 'public' }) + when :public_or_unlisted + statuses_index = statuses_index.filter.or(terms: { visibility: ['public', 'unlisted'] }) + end + definition = parsed_query.apply(statuses_index) if @options[:account_id].present? definition = definition.filter(term: { account_id: @options[:account_id] }) diff --git a/config/initializers/search_scope.rb b/config/initializers/search_scope.rb new file mode 100644 index 0000000000..3024405709 --- /dev/null +++ b/config/initializers/search_scope.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +Rails.application.configure do + config.x.search_scope = case + when ENV['SEARCH_SCOPE'] == 'public' + :public + when ENV['SEARCH_SCOPE'] == 'public_or_unlisted' + :public_or_unlisted + else + :classic + end +end