Merge branch 'kb_development' into kb_migration
This commit is contained in:
commit
24ee2fd4d7
26 changed files with 238 additions and 35 deletions
|
@ -157,6 +157,6 @@ class AccountsIndex < Chewy::Index
|
|||
field(:domain, type: 'keyword', value: ->(account) { account.domain || '' })
|
||||
field(:display_name, type: 'text', analyzer: 'verbatim') { field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'verbatim' }
|
||||
field(:username, type: 'text', analyzer: 'verbatim', value: ->(account) { [account.username, account.domain].compact.join('@') }) { field :edge_ngram, type: 'text', analyzer: 'edge_ngram', search_analyzer: 'verbatim' }
|
||||
field(:text, type: 'text', analyzer: 'sudachi_analyzer', value: ->(account) { account.searchable_text }) { field :stemmed, type: 'text', analyzer: 'natural' }
|
||||
field(:text, type: 'text', analyzer: 'sudachi_analyzer', value: ->(account) { account.searchable_text })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -144,12 +144,12 @@ class PublicStatusesIndex < Chewy::Index
|
|||
index_scope ::Status.unscoped
|
||||
.kept
|
||||
.indexable
|
||||
.includes(:media_attachments, :preloadable_poll, :preview_cards, :tags)
|
||||
.includes(:media_attachments, :preloadable_poll, :preview_cards, :tags, :account)
|
||||
|
||||
root date_detection: false do
|
||||
field(:id, type: 'long')
|
||||
field(:account_id, type: 'long')
|
||||
field(:text, type: 'text', analyzer: 'sudachi_analyzer', value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: 'sudachi_analyzer') }
|
||||
field(:text, type: 'text', analyzer: 'sudachi_analyzer', value: ->(status) { status.searchable_text })
|
||||
field(:tags, type: 'text', analyzer: 'hashtag', value: ->(status) { status.tags.map(&:display_name) })
|
||||
field(:language, type: 'keyword')
|
||||
field(:domain, type: 'keyword', value: ->(status) { status.account.domain || '' })
|
||||
|
|
|
@ -145,6 +145,7 @@ class StatusesIndex < Chewy::Index
|
|||
settings index: index_preset(refresh_interval: '30s', number_of_shards: 5), analysis: Rails.env.test? ? DEVELOPMENT_SETTINGS : PRODUCTION_SETTINGS
|
||||
|
||||
index_scope ::Status.unscoped.kept.without_reblogs.includes(
|
||||
:account,
|
||||
:media_attachments,
|
||||
:preview_cards,
|
||||
:local_mentioned,
|
||||
|
@ -160,17 +161,26 @@ class StatusesIndex < Chewy::Index
|
|||
if status.searchability == 'direct'
|
||||
status.searchable_by.empty?
|
||||
else
|
||||
status.searchability == 'limited' ? status.account.domain.present? : false
|
||||
status.searchability == 'limited' ? !status.local? : false
|
||||
end
|
||||
}
|
||||
|
||||
root date_detection: false do
|
||||
field(:id, type: 'long')
|
||||
field(:account_id, type: 'long')
|
||||
field(:text, type: 'text', analyzer: 'sudachi_analyzer', value: ->(status) { status.searchable_text }) { field(:stemmed, type: 'text', analyzer: 'sudachi_analyzer') }
|
||||
field(:text, type: 'text', analyzer: 'sudachi_analyzer', value: ->(status) { status.searchable_text })
|
||||
field(:tags, type: 'text', analyzer: 'hashtag', value: ->(status) { status.tags.map(&:display_name) })
|
||||
field(:searchable_by, type: 'long', value: ->(status) { status.searchable_by })
|
||||
field(:mentioned_by, type: 'long', value: ->(status) { status.mentioned_by })
|
||||
field(:favourited_by, type: 'long', value: ->(status) { status.favourited_by })
|
||||
field(:reblogged_by, type: 'long', value: ->(status) { status.reblogged_by })
|
||||
field(:bookmarked_by, type: 'long', value: ->(status) { status.bookmarked_by })
|
||||
field(:bookmark_categoried_by, type: 'long', value: ->(status) { status.bookmark_categoried_by })
|
||||
field(:emoji_reacted_by, type: 'long', value: ->(status) { status.emoji_reacted_by })
|
||||
field(:referenced_by, type: 'long', value: ->(status) { status.referenced_by })
|
||||
field(:voted_by, type: 'long', value: ->(status) { status.voted_by })
|
||||
field(:searchability, type: 'keyword', value: ->(status) { status.compute_searchability })
|
||||
field(:visibility, type: 'keyword', value: ->(status) { status.searchable_visibility })
|
||||
field(:language, type: 'keyword')
|
||||
field(:domain, type: 'keyword', value: ->(status) { status.account.domain || '' })
|
||||
field(:properties, type: 'keyword', value: ->(status) { status.searchable_properties })
|
||||
|
|
|
@ -59,13 +59,15 @@ class Search extends PureComponent {
|
|||
defaultOptions = [
|
||||
{ label: <><mark>has:</mark> <FormattedList type='disjunction' value={['media', 'poll', 'embed']} /></>, action: e => { e.preventDefault(); this._insertText('has:') } },
|
||||
{ label: <><mark>is:</mark> <FormattedList type='disjunction' value={['reply', 'sensitive']} /></>, action: e => { e.preventDefault(); this._insertText('is:') } },
|
||||
{ label: <><mark>my:</mark> <FormattedList type='disjunction' value={['favourited', 'bookmarked', 'boosted']} /></>, action: e => { e.preventDefault(); this._insertText('my:') } },
|
||||
{ label: <><mark>language:</mark> <FormattedMessage id='search_popout.language_code' defaultMessage='ISO language code' /></>, action: e => { e.preventDefault(); this._insertText('language:') } },
|
||||
{ label: <><mark>from:</mark> <FormattedMessage id='search_popout.user' defaultMessage='user' /></>, action: e => { e.preventDefault(); this._insertText('from:') } },
|
||||
{ label: <><mark>domain:</mark> <FormattedMessage id='search_popout.domain' defaultMessage='domain' /></>, action: e => { e.preventDefault(); this._insertText('domain:') } },
|
||||
{ label: <><mark>before:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('before:') } },
|
||||
{ label: <><mark>during:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('during:') } },
|
||||
{ label: <><mark>after:</mark> <FormattedMessage id='search_popout.specific_date' defaultMessage='specific date' /></>, action: e => { e.preventDefault(); this._insertText('after:') } },
|
||||
{ label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:') } }
|
||||
{ label: <><mark>in:</mark> <FormattedList type='disjunction' value={['all', 'library']} /></>, action: e => { e.preventDefault(); this._insertText('in:') } },
|
||||
{ label: <><mark>order:</mark> <FormattedList type='disjunction' value={['desc', 'asc']} /></>, action: e => { e.preventDefault(); this._insertText('order:') } },
|
||||
];
|
||||
|
||||
setRef = c => {
|
||||
|
|
|
@ -65,7 +65,10 @@ const appendToBookmarkCategoryStatusesById = (state, bookmarkCategoryId, statuse
|
|||
};
|
||||
|
||||
const removeStatusFromBookmarkCategoryById = (state, bookmarkCategoryId, status) => {
|
||||
return state.updateIn([bookmarkCategoryId, 'items'], items => items.delete(status));
|
||||
if (state.getIn([bookmarkCategoryId, 'items'])) {
|
||||
return state.updateIn([bookmarkCategoryId, 'items'], items => items.delete(status));
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
const removeStatusFromAllBookmarkCategories = (state, status) => {
|
||||
|
|
|
@ -493,7 +493,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
|||
references = @object['references'].nil? ? [] : ActivityPub::FetchReferencesService.new.call(@status, @object['references'])
|
||||
quote = @object['quote'] || @object['quoteUrl'] || @object['quoteURL'] || @object['_misskey_quote']
|
||||
references << quote if quote
|
||||
ProcessReferencesWorker.perform_async(@status.id, [], references)
|
||||
|
||||
ProcessReferencesService.perform_worker_async(@status, [], references)
|
||||
end
|
||||
|
||||
def join_group!
|
||||
|
|
|
@ -9,7 +9,7 @@ class ActivityPub::Activity::Like < ActivityPub::Activity
|
|||
|
||||
return if @original_status.nil? || delete_arrived_first?(@json['id']) || reject_favourite?
|
||||
|
||||
if shortcode.nil?
|
||||
if shortcode.nil? || !Setting.enable_emoji_reaction
|
||||
process_favourite
|
||||
else
|
||||
process_emoji_reaction
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
class Importer::BaseImporter
|
||||
# @param [Integer] batch_size
|
||||
# @param [Concurrent::ThreadPoolExecutor] executor
|
||||
def initialize(batch_size:, executor:)
|
||||
def initialize(batch_size:, executor:, full: true, from: nil, to: nil)
|
||||
@batch_size = batch_size
|
||||
@executor = executor
|
||||
@full = full
|
||||
@from = from.to_date if from.present?
|
||||
@to = to.to_date if to.present?
|
||||
@wait_for = Concurrent::Set.new
|
||||
end
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ class Importer::PublicStatusesIndexImporter < Importer::BaseImporter
|
|||
end
|
||||
|
||||
def scope
|
||||
Status.indexable.reorder(nil)
|
||||
to_index = Status.indexable.reorder(nil)
|
||||
to_index = to_index.where('statuses.created_at >= ?', @from) if @from.present?
|
||||
to_index = to_index.where('statuses.created_at < ?', @to) if @to.present?
|
||||
to_index
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,11 +17,13 @@ class Importer::StatusesIndexImporter < Importer::BaseImporter
|
|||
|
||||
bulk = ActiveRecord::Base.connection_pool.with_connection do
|
||||
to_index = index.adapter.default_scope.where(id: status_ids)
|
||||
to_index = to_index.where('created_at >= ?', @from) if @from.present?
|
||||
to_index = to_index.where('created_at < ?', @to) if @to.present?
|
||||
crutches = Chewy::Index::Crutch::Crutches.new index, to_index
|
||||
to_index.map do |object|
|
||||
# This is unlikely to happen, but the post may have been
|
||||
# un-interacted with since it was queued for indexing
|
||||
if object.searchable_by.empty?
|
||||
if object.searchable_by.empty? && %w(public private).exclude?(object.searchability)
|
||||
deleted += 1
|
||||
{ delete: { _id: object.id } }
|
||||
else
|
||||
|
@ -49,13 +51,15 @@ class Importer::StatusesIndexImporter < Importer::BaseImporter
|
|||
end
|
||||
|
||||
def scopes
|
||||
[
|
||||
targets = [
|
||||
local_statuses_scope,
|
||||
local_mentions_scope,
|
||||
local_favourites_scope,
|
||||
local_votes_scope,
|
||||
local_bookmarks_scope,
|
||||
]
|
||||
targets << remote_searchable_scope if @full
|
||||
targets
|
||||
end
|
||||
|
||||
def local_mentions_scope
|
||||
|
@ -77,4 +81,8 @@ 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 remote_searchable_scope
|
||||
Status.remote_dynamic_searchability.select('"statuses"."id", COALESCE("statuses"."reblog_of_id", "statuses"."id") AS status_id')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,7 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
SUPPORTED_PREFIXES = %w(
|
||||
has
|
||||
is
|
||||
my
|
||||
language
|
||||
from
|
||||
before
|
||||
|
@ -11,6 +12,8 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
during
|
||||
in
|
||||
domain
|
||||
order
|
||||
searchability
|
||||
).freeze
|
||||
|
||||
class Query
|
||||
|
@ -34,6 +37,18 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
search
|
||||
end
|
||||
|
||||
def order_by
|
||||
return @order_by if @order_by
|
||||
|
||||
@order_by = 'desc'
|
||||
order_clauses.each { |clause| @order_by = clause.term }
|
||||
@order_by
|
||||
end
|
||||
|
||||
def valid
|
||||
must_clauses.any? || must_not_clauses.any? || filter_clauses.any?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def clauses_by_operator
|
||||
|
@ -56,6 +71,10 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
clauses_by_operator.fetch(:filter, [])
|
||||
end
|
||||
|
||||
def order_clauses
|
||||
clauses_by_operator.fetch(:order, [])
|
||||
end
|
||||
|
||||
def indexes
|
||||
case @flags['in']
|
||||
when 'library'
|
||||
|
@ -214,6 +233,7 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
if @term.start_with?('#')
|
||||
{ match: { tags: { query: @term, operator: 'and' } } }
|
||||
else
|
||||
# Memo for checking when manually merge
|
||||
# { multi_match: { type: 'most_fields', query: @term, fields: ['text', 'text.stemmed'], operator: 'and' } }
|
||||
{ match_phrase: { text: { query: @term } } }
|
||||
end
|
||||
|
@ -236,11 +256,12 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
class PrefixClause
|
||||
attr_reader :operator, :prefix, :term
|
||||
|
||||
def initialize(prefix, operator, term, options = {})
|
||||
def initialize(prefix, operator, term, options = {}) # rubocop:disable Metrics/CyclomaticComplexity
|
||||
@prefix = prefix
|
||||
@negated = operator == '-'
|
||||
@options = options
|
||||
@operator = :filter
|
||||
@statuses_index_only = false
|
||||
|
||||
case prefix
|
||||
when 'has', 'is'
|
||||
|
@ -274,13 +295,67 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
when 'in'
|
||||
@operator = :flag
|
||||
@term = term
|
||||
when 'my'
|
||||
@type = :term
|
||||
@term = @options[:current_account]&.id
|
||||
@statuses_index_only = true
|
||||
case term
|
||||
when 'favourited', 'favorited', 'fav'
|
||||
@filter = :favourited_by
|
||||
when 'boosted', 'bt'
|
||||
@filter = :reblogged_by
|
||||
when 'replied', 'mentioned', 're'
|
||||
@filter = :mentioned_by
|
||||
when 'referenced', 'ref'
|
||||
@filter = :referenced_by
|
||||
when 'emoji_reacted', 'stamped', 'stamp'
|
||||
@filter = :emoji_reacted_by
|
||||
when 'bookmarked', 'bm'
|
||||
@filter = :bookmarked_by
|
||||
when 'categoried', 'bmc'
|
||||
@filter = :bookmark_categoried_by
|
||||
when 'voted', 'vote'
|
||||
@filter = :voted_by
|
||||
when 'interacted', 'act'
|
||||
@filter = :searchable_by
|
||||
else
|
||||
raise "Unknown prefix: my:#{term}"
|
||||
end
|
||||
when 'order'
|
||||
@operator = :order
|
||||
@term = case term
|
||||
when 'asc'
|
||||
term
|
||||
else
|
||||
'desc'
|
||||
end
|
||||
when 'searchability'
|
||||
@filter = :searchablity
|
||||
@type = :terms
|
||||
@statuses_index_only = true
|
||||
@term = case term
|
||||
when 'public'
|
||||
%w(public private direct limited)
|
||||
when 'private'
|
||||
%w(private direct limited)
|
||||
when 'direct'
|
||||
%w(direct limited)
|
||||
else
|
||||
%w(limited)
|
||||
end
|
||||
else
|
||||
raise "Unknown prefix: #{prefix}"
|
||||
end
|
||||
end
|
||||
|
||||
def to_query
|
||||
if @negated
|
||||
if @statuses_index_only
|
||||
if @negated
|
||||
{ bool: { must_not: [{ term: { _index: StatusesIndex.index_name } }, { @type => { @filter => @term } }] } }
|
||||
else
|
||||
{ bool: { must: [{ term: { _index: StatusesIndex.index_name } }, { @type => { @filter => @term } }] } }
|
||||
end
|
||||
elsif @negated
|
||||
{ bool: { must_not: { @type => { @filter => @term } } } }
|
||||
else
|
||||
{ @type => { @filter => @term } }
|
||||
|
@ -302,7 +377,7 @@ class SearchQueryTransformer < Parslet::Transform
|
|||
end
|
||||
|
||||
def domain_from_term(term)
|
||||
return '' if %w(local me).include?(term)
|
||||
return '' if ['local', 'me', Rails.configuration.x.local_domain].include?(term)
|
||||
|
||||
term
|
||||
end
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
#
|
||||
|
||||
class BookmarkCategoryStatus < ApplicationRecord
|
||||
include Paginable
|
||||
|
||||
update_index('statuses', :status) if Chewy.enabled?
|
||||
|
||||
belongs_to :bookmark_category
|
||||
belongs_to :status
|
||||
belongs_to :bookmark
|
||||
|
|
|
@ -5,6 +5,7 @@ module StatusSearchConcern
|
|||
|
||||
included do
|
||||
scope :indexable, -> { without_reblogs.where(visibility: [:public, :login], searchability: nil).joins(:account).where(account: { indexable: true }) }
|
||||
scope :remote_dynamic_searchability, -> { remote.where(searchability: [:public, :private]) }
|
||||
end
|
||||
|
||||
def searchable_by
|
||||
|
@ -13,18 +14,52 @@ module StatusSearchConcern
|
|||
|
||||
ids << account_id if local?
|
||||
|
||||
ids += local_mentioned.pluck(:id)
|
||||
ids += local_favorited.pluck(:id)
|
||||
ids += local_reblogged.pluck(:id)
|
||||
ids += local_bookmarked.pluck(:id)
|
||||
ids += local_emoji_reacted.pluck(:id)
|
||||
ids += local_referenced.pluck(:id)
|
||||
ids += preloadable_poll.local_voters.pluck(:id) if preloadable_poll.present?
|
||||
ids += mentioned_by
|
||||
ids += favourited_by
|
||||
ids += reblogged_by
|
||||
ids += bookmarked_by
|
||||
ids += emoji_reacted_by
|
||||
ids += referenced_by
|
||||
ids += voted_by if preloadable_poll.present?
|
||||
|
||||
ids.uniq
|
||||
end
|
||||
end
|
||||
|
||||
def mentioned_by
|
||||
@mentioned_by ||= local_mentioned.pluck(:id)
|
||||
end
|
||||
|
||||
def favourited_by
|
||||
@favourited_by ||= local_favorited.pluck(:id)
|
||||
end
|
||||
|
||||
def reblogged_by
|
||||
@reblogged_by ||= local_reblogged.pluck(:id)
|
||||
end
|
||||
|
||||
def bookmarked_by
|
||||
@bookmarked_by ||= local_bookmarked.pluck(:id)
|
||||
end
|
||||
|
||||
def bookmark_categoried_by
|
||||
@bookmark_categoried_by ||= local_bookmark_categoried.pluck(:id).uniq
|
||||
end
|
||||
|
||||
def emoji_reacted_by
|
||||
@emoji_reacted_by ||= local_emoji_reacted.pluck(:id)
|
||||
end
|
||||
|
||||
def referenced_by
|
||||
@referenced_by ||= local_referenced.pluck(:id)
|
||||
end
|
||||
|
||||
def voted_by
|
||||
return [] if preloadable_poll.blank?
|
||||
|
||||
@voted_by ||= preloadable_poll.local_voters.pluck(:id)
|
||||
end
|
||||
|
||||
def searchable_text
|
||||
[
|
||||
spoiler_text,
|
||||
|
|
|
@ -86,6 +86,7 @@ class Status < ApplicationRecord
|
|||
has_many :referenced_by_statuses, through: :referenced_by_status_objects, class_name: 'Status', source: :status
|
||||
has_many :capability_tokens, class_name: 'StatusCapabilityToken', inverse_of: :status, dependent: :destroy
|
||||
has_many :bookmark_category_relationships, class_name: 'BookmarkCategoryStatus', inverse_of: :status, dependent: :destroy
|
||||
has_many :bookmark_categories, class_name: 'BookmarkCategory', through: :bookmark_category_relationships, source: :bookmark_category
|
||||
has_many :joined_bookmark_categories, class_name: 'BookmarkCategory', through: :bookmark_category_relationships, source: :bookmark_category
|
||||
|
||||
# Those associations are used for the private search index
|
||||
|
@ -93,6 +94,7 @@ class Status < ApplicationRecord
|
|||
has_many :local_favorited, -> { merge(Account.local) }, through: :favourites, source: :account
|
||||
has_many :local_reblogged, -> { merge(Account.local) }, through: :reblogs, source: :account
|
||||
has_many :local_bookmarked, -> { merge(Account.local) }, through: :bookmarks, source: :account
|
||||
has_many :local_bookmark_categoried, -> { merge(Account.local) }, through: :bookmark_categories, source: :account
|
||||
has_many :local_emoji_reacted, -> { merge(Account.local) }, through: :emoji_reactions, source: :account
|
||||
has_many :local_referenced, -> { merge(Account.local) }, through: :referenced_by_statuses, source: :account
|
||||
|
||||
|
@ -435,6 +437,12 @@ class Status < ApplicationRecord
|
|||
compute_searchability
|
||||
end
|
||||
|
||||
def searchable_visibility
|
||||
return limited_scope if limited_visibility? && !none_limited?
|
||||
|
||||
visibility
|
||||
end
|
||||
|
||||
class << self
|
||||
def selectable_visibilities
|
||||
visibilities.keys - %w(direct limited)
|
||||
|
|
|
@ -48,7 +48,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
store[:display_media] = object.current_account.user.setting_display_media
|
||||
store[:display_media_expand] = object.current_account.user.setting_display_media_expand
|
||||
store[:expand_spoilers] = object.current_account.user.setting_expand_spoilers
|
||||
store[:enable_emoji_reaction] = object.current_account.user.setting_enable_emoji_reaction
|
||||
store[:enable_emoji_reaction] = object.current_account.user.setting_enable_emoji_reaction && Setting.enable_emoji_reaction
|
||||
store[:show_emoji_reaction_on_timeline] = object.current_account.user.setting_show_emoji_reaction_on_timeline
|
||||
store[:enable_login_privacy] = object.current_account.user.setting_enable_login_privacy
|
||||
store[:enable_dtl_menu] = object.current_account.user.setting_enable_dtl_menu
|
||||
|
@ -66,6 +66,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
store[:reduce_motion] = Setting.reduce_motion
|
||||
store[:use_blurhash] = Setting.use_blurhash
|
||||
store[:enable_emoji_reaction] = Setting.enable_emoji_reaction
|
||||
store[:show_emoji_reaction_on_timeline] = Setting.enable_emoji_reaction
|
||||
end
|
||||
|
||||
store[:disabled_account_id] = object.disabled_account.id.to_s if object.disabled_account
|
||||
|
|
|
@ -103,7 +103,9 @@ class REST::StatusSerializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def status_references_count
|
||||
status_reference_ids.size
|
||||
return status_reference_ids.size if status_reference_ids.any?
|
||||
|
||||
Rails.cache.exist?("status_reference:#{object.id}") ? 1 : 0
|
||||
end
|
||||
|
||||
def reblogs_count
|
||||
|
|
|
@ -254,7 +254,8 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
|
|||
references = @json['references'].nil? ? [] : ActivityPub::FetchReferencesService.new.call(@status, @json['references'])
|
||||
quote = @json['quote'] || @json['quoteUrl'] || @json['quoteURL'] || @json['_misskey_quote']
|
||||
references << quote if quote
|
||||
ProcessReferencesWorker.perform_async(@status.id, [], references)
|
||||
|
||||
ProcessReferencesService.perform_worker_async(@status, [], references)
|
||||
end
|
||||
|
||||
def expected_type?
|
||||
|
|
|
@ -17,7 +17,7 @@ module Payloadable
|
|||
payload = ActiveModelSerializers::SerializableResource.new(record, options.merge(serializer: serializer, adapter: ActivityPub::Adapter)).as_json
|
||||
object = record.respond_to?(:virtual_object) ? record.virtual_object : record
|
||||
|
||||
if (object.respond_to?(:sign?) && object.sign?) && signer && (always_sign || signing_enabled?)
|
||||
if ((object.respond_to?(:sign?) && object.sign?) && signer && (always_sign || signing_enabled?)) || object.is_a?(String)
|
||||
ActivityPub::LinkedDataSignature.new(payload).sign!(signer, sign_with: sign_with)
|
||||
else
|
||||
payload
|
||||
|
|
|
@ -187,8 +187,8 @@ class PostStatusService < BaseService
|
|||
@account.user.update!(settings_attributes: { default_privacy: @options[:visibility] }) if @account.user&.setting_stay_privacy && !@status.reply? && %i(public public_unlisted login unlisted private).include?(@status.visibility.to_sym) && @status.visibility.to_s != @account.user&.setting_default_privacy && !@dtl
|
||||
|
||||
process_hashtags_service.call(@status)
|
||||
ProcessReferencesWorker.perform_async(@status.id, @reference_ids, [])
|
||||
Trends.tags.register(@status)
|
||||
ProcessReferencesService.perform_worker_async(@status, @reference_ids, [])
|
||||
LinkCrawlWorker.perform_async(@status.id)
|
||||
DistributionWorker.perform_async(@status.id)
|
||||
ActivityPub::DistributionWorker.perform_async(@status.id)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
class ProcessReferencesService < BaseService
|
||||
include Payloadable
|
||||
include FormattingHelper
|
||||
|
||||
DOMAIN = ENV['WEB_DOMAIN'] || ENV.fetch('LOCAL_DOMAIN', nil)
|
||||
REFURL_EXP = /(RT|QT|BT|RN|RE)((:|;)?\s+|:|;)(#{URI::DEFAULT_PARSER.make_regexp(%w(http https))})/
|
||||
|
@ -23,9 +24,22 @@ class ProcessReferencesService < BaseService
|
|||
@status.save!
|
||||
end
|
||||
|
||||
Rails.cache.delete("status_reference:#{@status.id}")
|
||||
|
||||
create_notifications!
|
||||
end
|
||||
|
||||
def self.need_process?(status, reference_parameters, urls)
|
||||
reference_parameters.any? || (urls || []).any? || FormattingHelper.extract_status_plain_text(status).scan(REFURL_EXP).pluck(3).uniq.any?
|
||||
end
|
||||
|
||||
def self.perform_worker_async(status, reference_parameters, urls)
|
||||
return unless need_process?(status, reference_parameters, urls)
|
||||
|
||||
Rails.cache.write("status_reference:#{status.id}", true, expires_in: 10.minutes)
|
||||
ProcessReferencesWorker.perform_async(status.id, reference_parameters, urls)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def references
|
||||
|
@ -51,7 +65,7 @@ class ProcessReferencesService < BaseService
|
|||
|
||||
def fetch_statuses!(urls)
|
||||
(urls + @urls)
|
||||
.map { |url| ResolveURLService.new.call(url) }
|
||||
.map { |url| ResolveURLService.new.call(url, on_behalf_of: @status.account) }
|
||||
.filter { |status| status }
|
||||
end
|
||||
|
||||
|
|
|
@ -16,8 +16,11 @@ class StatusesSearchService < BaseService
|
|||
private
|
||||
|
||||
def status_search_results
|
||||
request = parsed_query.request
|
||||
results = request.collapse(field: :id).order(id: { order: :desc }).limit(@limit).offset(@offset).objects.compact
|
||||
query = parsed_query
|
||||
request = query.request
|
||||
return [] unless query.valid
|
||||
|
||||
results = request.collapse(field: :id).order(id: { order: query.order_by }).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)
|
||||
|
|
|
@ -161,7 +161,8 @@ class UpdateStatusService < BaseService
|
|||
|
||||
def update_references!
|
||||
reference_ids = (@options[:status_reference_ids] || []).map(&:to_i).filter(&:positive?)
|
||||
ProcessReferencesWorker.perform_async(@status.id, reference_ids, [])
|
||||
|
||||
ProcessReferencesService.perform_worker_async(@status, reference_ids, [])
|
||||
end
|
||||
|
||||
def update_metadata!
|
||||
|
|
|
@ -25,8 +25,8 @@ module Mastodon::CLI
|
|||
say('Let the WAR begin.', :red)
|
||||
end
|
||||
|
||||
desc 'kokuraan', 'Ohagi is kokuraan'
|
||||
def kokuraan
|
||||
desc 'oguraan', 'Ohagi is oguraan'
|
||||
def oguraan
|
||||
say('I hate you.', :yellow)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -20,6 +20,9 @@ module Mastodon::CLI
|
|||
option :import, type: :boolean, default: true, desc: 'Import data from the database to the index'
|
||||
option :clean, type: :boolean, default: true, desc: 'Remove outdated documents from the index'
|
||||
option :reset_chewy, type: :boolean, default: false, desc: "Reset Chewy's internal index"
|
||||
option :full, type: :boolean, default: false, desc: 'Import full data over Mastodon default importer'
|
||||
option :from, type: :string, default: nil, desc: 'Statuses start date'
|
||||
option :to, type: :string, default: nil, desc: 'Statuses end date'
|
||||
desc 'deploy', 'Create or upgrade Elasticsearch indices and populate them'
|
||||
long_desc <<~LONG_DESC
|
||||
If Elasticsearch is empty, this command will create the necessary indices
|
||||
|
@ -41,7 +44,7 @@ module Mastodon::CLI
|
|||
end
|
||||
|
||||
pool = Concurrent::FixedThreadPool.new(options[:concurrency], max_queue: options[:concurrency] * 10)
|
||||
importers = indices.index_with { |index| "Importer::#{index.name}Importer".constantize.new(batch_size: options[:batch_size], executor: pool) }
|
||||
importers = indices.index_with { |index| "Importer::#{index.name}Importer".constantize.new(batch_size: options[:batch_size], executor: pool, full: options[:full], from: options[:from], to: options[:to]) }
|
||||
progress = ProgressBar.create(total: nil, format: '%t%c/%u |%b%i| %e (%r docs/s)', autofinish: false)
|
||||
|
||||
Chewy::Stash::Specification.reset! if options[:reset_chewy]
|
||||
|
|
|
@ -21,6 +21,19 @@ describe Api::V1::CirclesController do
|
|||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
circle_id = circle.id.to_s
|
||||
Fabricate(:circle)
|
||||
get :index
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
circle_ids = body_as_json.pluck(:id)
|
||||
expect(circle_ids.size).to eq 1
|
||||
expect(circle_ids).to include circle_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the wrong user context' do
|
||||
|
|
|
@ -21,6 +21,19 @@ describe Api::V1::ListsController do
|
|||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
it 'returns http success' do
|
||||
list_id = list.id.to_s
|
||||
Fabricate(:list)
|
||||
get :index
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
list_ids = body_as_json.pluck(:id)
|
||||
expect(list_ids.size).to eq 1
|
||||
expect(list_ids).to include list_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the wrong user context' do
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue