Merge branch 'main' into glitch-soc/merge-upstream
This commit is contained in:
@@ -37,18 +37,29 @@ class PublicStatusesIndex < Chewy::Index
|
||||
english_stemmer
|
||||
),
|
||||
},
|
||||
|
||||
hashtag: {
|
||||
tokenizer: 'keyword',
|
||||
filter: %w(
|
||||
word_delimiter_graph
|
||||
lowercase
|
||||
asciifolding
|
||||
cjk_width
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
index_scope ::Status.unscoped
|
||||
.kept
|
||||
.indexable
|
||||
.includes(:media_attachments, :preloadable_poll, :preview_cards)
|
||||
.includes(:media_attachments, :preloadable_poll, :preview_cards, :tags)
|
||||
|
||||
root date_detection: false do
|
||||
field(:id, type: 'long')
|
||||
field(:account_id, type: 'long')
|
||||
field(:text, type: 'text', analyzer: 'verbatim', value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: 'content') }
|
||||
field(:tags, type: 'text', analyzer: 'hashtag', value: ->(status) { status.tags.map(&:display_name) })
|
||||
field(:language, type: 'keyword')
|
||||
field(:properties, type: 'keyword', value: ->(status) { status.searchable_properties })
|
||||
field(:created_at, type: 'date')
|
||||
|
||||
@@ -37,15 +37,26 @@ class StatusesIndex < Chewy::Index
|
||||
english_stemmer
|
||||
),
|
||||
},
|
||||
|
||||
hashtag: {
|
||||
tokenizer: 'keyword',
|
||||
filter: %w(
|
||||
word_delimiter_graph
|
||||
lowercase
|
||||
asciifolding
|
||||
cjk_width
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
index_scope ::Status.unscoped.kept.without_reblogs.includes(:media_attachments, :preview_cards, :local_mentioned, :local_favorited, :local_reblogged, :local_bookmarked, preloadable_poll: :local_voters), delete_if: ->(status) { status.searchable_by.empty? }
|
||||
index_scope ::Status.unscoped.kept.without_reblogs.includes(:media_attachments, :preview_cards, :local_mentioned, :local_favorited, :local_reblogged, :local_bookmarked, :tags, preloadable_poll: :local_voters), delete_if: ->(status) { status.searchable_by.empty? }
|
||||
|
||||
root date_detection: false do
|
||||
field(:id, type: 'long')
|
||||
field(:account_id, type: 'long')
|
||||
field(:text, type: 'text', analyzer: 'verbatim', value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: 'content') }
|
||||
field(:tags, type: 'text', analyzer: 'hashtag', value: ->(status) { status.tags.map(&:display_name) })
|
||||
field(:searchable_by, type: 'long', value: ->(status) { status.searchable_by })
|
||||
field(:language, type: 'keyword')
|
||||
field(:properties, type: 'keyword', value: ->(status) { status.searchable_properties })
|
||||
|
||||
+15
-9
@@ -5,12 +5,21 @@ class TagsIndex < Chewy::Index
|
||||
analyzer: {
|
||||
content: {
|
||||
tokenizer: 'keyword',
|
||||
filter: %w(lowercase asciifolding cjk_width),
|
||||
filter: %w(
|
||||
word_delimiter_graph
|
||||
lowercase
|
||||
asciifolding
|
||||
cjk_width
|
||||
),
|
||||
},
|
||||
|
||||
edge_ngram: {
|
||||
tokenizer: 'edge_ngram',
|
||||
filter: %w(lowercase asciifolding cjk_width),
|
||||
filter: %w(
|
||||
lowercase
|
||||
asciifolding
|
||||
cjk_width
|
||||
),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -30,12 +39,9 @@ class TagsIndex < Chewy::Index
|
||||
end
|
||||
|
||||
root date_detection: false do
|
||||
field :name, type: 'text', analyzer: 'content' do
|
||||
field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content'
|
||||
end
|
||||
|
||||
field :reviewed, type: 'boolean', value: ->(tag) { tag.reviewed? }
|
||||
field :usage, type: 'long', value: ->(tag, crutches) { tag.history.aggregate(crutches.time_period).accounts }
|
||||
field :last_status_at, type: 'date', value: ->(tag) { tag.last_status_at || tag.created_at }
|
||||
field(:name, type: 'text', analyzer: 'content', value: :display_name) { field(:edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'content') }
|
||||
field(:reviewed, type: 'boolean', value: ->(tag) { tag.reviewed? })
|
||||
field(:usage, type: 'long', value: ->(tag, crutches) { tag.history.aggregate(crutches.time_period).accounts })
|
||||
field(:last_status_at, type: 'date', value: ->(tag) { tag.last_status_at || tag.created_at })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -193,7 +193,6 @@ module LanguagesHelper
|
||||
cnr: ['Montenegrin', 'crnogorski'].freeze,
|
||||
jbo: ['Lojban', 'la .lojban.'].freeze,
|
||||
kab: ['Kabyle', 'Taqbaylit'].freeze,
|
||||
kmr: ['Kurmanji (Kurdish)', 'Kurmancî'].freeze,
|
||||
ldn: ['Láadan', 'Láadan'].freeze,
|
||||
lfn: ['Lingua Franca Nova', 'lingua franca nova'].freeze,
|
||||
sco: ['Scots', 'Scots'].freeze,
|
||||
|
||||
@@ -228,20 +228,20 @@
|
||||
color: lighten($lighter-text-color, 7%);
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
&.active {
|
||||
color: $highlight-text-color;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
color: $highlight-text-color;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
color: $highlight-text-color;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
color: lighten($highlight-text-color, 13%);
|
||||
}
|
||||
&.disabled {
|
||||
color: lighten($highlight-text-color, 13%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3272,8 +3272,8 @@ $ui-header-height: 55px;
|
||||
}
|
||||
|
||||
.switch-to-advanced {
|
||||
color: $classic-primary-color;
|
||||
background-color: $classic-base-color;
|
||||
color: $light-text-color;
|
||||
background-color: $ui-base-color;
|
||||
padding: 15px;
|
||||
border-radius: 4px;
|
||||
margin-top: 4px;
|
||||
|
||||
@@ -9,23 +9,90 @@ class SearchQueryTransformer < Parslet::Transform
|
||||
before
|
||||
after
|
||||
during
|
||||
in
|
||||
).freeze
|
||||
|
||||
class Query
|
||||
attr_reader :must_not_clauses, :must_clauses, :filter_clauses
|
||||
def initialize(clauses, options = {})
|
||||
raise ArgumentError if options[:current_account].nil?
|
||||
|
||||
def initialize(clauses)
|
||||
grouped = clauses.compact.chunk(&:operator).to_h
|
||||
@must_not_clauses = grouped.fetch(:must_not, [])
|
||||
@must_clauses = grouped.fetch(:must, [])
|
||||
@filter_clauses = grouped.fetch(:filter, [])
|
||||
@clauses = clauses
|
||||
@options = options
|
||||
|
||||
flags_from_clauses!
|
||||
end
|
||||
|
||||
def apply(search)
|
||||
def request
|
||||
search = Chewy::Search::Request.new(*indexes).filter(default_filter)
|
||||
|
||||
must_clauses.each { |clause| search = search.query.must(clause.to_query) }
|
||||
must_not_clauses.each { |clause| search = search.query.must_not(clause.to_query) }
|
||||
filter_clauses.each { |clause| search = search.filter(**clause.to_query) }
|
||||
search.query.minimum_should_match(1)
|
||||
|
||||
search
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def clauses_by_operator
|
||||
@clauses_by_operator ||= @clauses.compact.chunk(&:operator).to_h
|
||||
end
|
||||
|
||||
def flags_from_clauses!
|
||||
@flags = clauses_by_operator.fetch(:flag, []).to_h { |clause| [clause.prefix, clause.term] }
|
||||
end
|
||||
|
||||
def must_clauses
|
||||
clauses_by_operator.fetch(:must, [])
|
||||
end
|
||||
|
||||
def must_not_clauses
|
||||
clauses_by_operator.fetch(:must_not, [])
|
||||
end
|
||||
|
||||
def filter_clauses
|
||||
clauses_by_operator.fetch(:filter, [])
|
||||
end
|
||||
|
||||
def indexes
|
||||
case @flags['in']
|
||||
when 'library'
|
||||
[StatusesIndex]
|
||||
else
|
||||
[PublicStatusesIndex, StatusesIndex]
|
||||
end
|
||||
end
|
||||
|
||||
def default_filter
|
||||
{
|
||||
bool: {
|
||||
should: [
|
||||
{
|
||||
term: {
|
||||
_index: PublicStatusesIndex.index_name,
|
||||
},
|
||||
},
|
||||
{
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
term: {
|
||||
_index: StatusesIndex.index_name,
|
||||
},
|
||||
},
|
||||
{
|
||||
term: {
|
||||
searchable_by: @options[:current_account].id,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
minimum_should_match: 1,
|
||||
},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -53,7 +120,11 @@ class SearchQueryTransformer < Parslet::Transform
|
||||
end
|
||||
|
||||
def to_query
|
||||
{ multi_match: { type: 'most_fields', query: @term, fields: ['text', 'text.stemmed'], operator: 'and' } }
|
||||
if @term.start_with?('#')
|
||||
{ match: { tags: { query: @term } } }
|
||||
else
|
||||
{ multi_match: { type: 'most_fields', query: @term, fields: ['text', 'text.stemmed'], operator: 'and' } }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -95,15 +166,18 @@ class SearchQueryTransformer < Parslet::Transform
|
||||
when 'before'
|
||||
@filter = :created_at
|
||||
@type = :range
|
||||
@term = { lt: term, time_zone: @options[:current_account]&.user_time_zone || 'UTC' }
|
||||
@term = { lt: term, time_zone: @options[:current_account]&.user_time_zone.presence || 'UTC' }
|
||||
when 'after'
|
||||
@filter = :created_at
|
||||
@type = :range
|
||||
@term = { gt: term, time_zone: @options[:current_account]&.user_time_zone || 'UTC' }
|
||||
@term = { gt: term, time_zone: @options[:current_account]&.user_time_zone.presence || 'UTC' }
|
||||
when 'during'
|
||||
@filter = :created_at
|
||||
@type = :range
|
||||
@term = { gte: term, lte: term, time_zone: @options[:current_account]&.user_time_zone || 'UTC' }
|
||||
@term = { gte: term, lte: term, time_zone: @options[:current_account]&.user_time_zone.presence || 'UTC' }
|
||||
when 'in'
|
||||
@operator = :flag
|
||||
@term = term
|
||||
else
|
||||
raise "Unknown prefix: #{prefix}"
|
||||
end
|
||||
@@ -172,6 +246,6 @@ class SearchQueryTransformer < Parslet::Transform
|
||||
end
|
||||
|
||||
rule(query: sequence(:clauses)) do
|
||||
Query.new(clauses)
|
||||
Query.new(clauses, current_account: current_account)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,20 +14,8 @@ class StatusesSearchService < BaseService
|
||||
private
|
||||
|
||||
def status_search_results
|
||||
definition = parsed_query.apply(
|
||||
Chewy::Search::Request.new(StatusesIndex, PublicStatusesIndex).filter(
|
||||
bool: {
|
||||
should: [
|
||||
publicly_searchable,
|
||||
non_publicly_searchable,
|
||||
],
|
||||
|
||||
minimum_should_match: 1,
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
results = definition.collapse(field: :id).order(id: { order: :desc }).limit(@limit).offset(@offset).objects.compact
|
||||
request = parsed_query.request
|
||||
results = request.collapse(field: :id).order(id: { order: :desc }).limit(@limit).offset(@offset).objects.compact
|
||||
account_ids = results.map(&:account_id)
|
||||
account_domains = results.map(&:account_domain)
|
||||
preloaded_relations = @account.relations_map(account_ids, account_domains)
|
||||
@@ -37,27 +25,6 @@ class StatusesSearchService < BaseService
|
||||
[]
|
||||
end
|
||||
|
||||
def publicly_searchable
|
||||
{
|
||||
term: { _index: PublicStatusesIndex.index_name },
|
||||
}
|
||||
end
|
||||
|
||||
def non_publicly_searchable
|
||||
{
|
||||
bool: {
|
||||
must: [
|
||||
{
|
||||
term: { _index: StatusesIndex.index_name },
|
||||
},
|
||||
{
|
||||
term: { searchable_by: @account.id },
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
def parsed_query
|
||||
SearchQueryTransformer.new.apply(SearchQueryParser.new.parse(@query), current_account: @account)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user