Merge branch 'kb_development' into kb_migration
This commit is contained in:
commit
86915f0cdb
9 changed files with 72 additions and 8 deletions
|
@ -30,7 +30,20 @@ class StatusesIndex < Chewy::Index
|
||||||
english_stemmer
|
english_stemmer
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
sudachi_analyzer: {
|
||||||
|
filter: [],
|
||||||
|
type: 'custom',
|
||||||
|
tokenizer: 'sudachi_tokenizer',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
tokenizer: {
|
||||||
|
sudachi_tokenizer: {
|
||||||
|
resources_path: '/etc/elasticsearch/sudachi',
|
||||||
|
split_mode: 'C',
|
||||||
|
type: 'sudachi_tokenizer',
|
||||||
|
discard_punctuation: 'true',
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# We do not use delete_if option here because it would call a method that we
|
# We do not use delete_if option here because it would call a method that we
|
||||||
|
@ -47,6 +60,11 @@ class StatusesIndex < Chewy::Index
|
||||||
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
crutch :emoji_reactions do |collection|
|
||||||
|
data = ::EmojiReaction.where(status_id: collection.map(&:id)).where(account: Account.local).pluck(:status_id, :account_id)
|
||||||
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||||
|
end
|
||||||
|
|
||||||
crutch :reblogs do |collection|
|
crutch :reblogs do |collection|
|
||||||
data = ::Status.where(reblog_of_id: collection.map(&:id)).where(account: Account.local).pluck(:reblog_of_id, :account_id)
|
data = ::Status.where(reblog_of_id: collection.map(&:id)).where(account: Account.local).pluck(:reblog_of_id, :account_id)
|
||||||
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
class Api::V2::SearchController < Api::BaseController
|
class Api::V2::SearchController < Api::BaseController
|
||||||
include Authorization
|
include Authorization
|
||||||
|
|
||||||
RESULTS_LIMIT = 20
|
RESULTS_LIMIT = 40
|
||||||
|
|
||||||
before_action -> { authorize_if_got_token! :read, :'read:search' }
|
before_action -> { authorize_if_got_token! :read, :'read:search' }
|
||||||
before_action :validate_search_params!
|
before_action :validate_search_params!
|
||||||
|
|
|
@ -46,7 +46,7 @@ export function submitSearch(type) {
|
||||||
params: {
|
params: {
|
||||||
q: value,
|
q: value,
|
||||||
resolve: signedIn,
|
resolve: signedIn,
|
||||||
limit: 5,
|
limit: 10,
|
||||||
type,
|
type,
|
||||||
},
|
},
|
||||||
}).then(response => {
|
}).then(response => {
|
||||||
|
|
|
@ -24,6 +24,7 @@ class SearchResults extends ImmutablePureComponent {
|
||||||
dismissSuggestion: PropTypes.func.isRequired,
|
dismissSuggestion: PropTypes.func.isRequired,
|
||||||
searchTerm: PropTypes.string,
|
searchTerm: PropTypes.string,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
noMoreResults: ImmutablePropTypes.map,
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
@ -44,6 +45,8 @@ class SearchResults extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleLoadMoreHashtags = () => this.props.expandSearch('hashtags');
|
handleLoadMoreHashtags = () => this.props.expandSearch('hashtags');
|
||||||
|
|
||||||
|
showMoreResults = (searchType) => this.props.noMoreResults ? !this.props.noMoreResults.get(searchType) : true;
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, results, suggestions, dismissSuggestion, searchTerm } = this.props;
|
const { intl, results, suggestions, dismissSuggestion, searchTerm } = this.props;
|
||||||
|
|
||||||
|
@ -75,26 +78,28 @@ class SearchResults extends ImmutablePureComponent {
|
||||||
|
|
||||||
if (results.get('accounts') && results.get('accounts').size > 0) {
|
if (results.get('accounts') && results.get('accounts').size > 0) {
|
||||||
count += results.get('accounts').size;
|
count += results.get('accounts').size;
|
||||||
|
const showMore = this.showMoreResults('accounts');
|
||||||
accounts = (
|
accounts = (
|
||||||
<div className='search-results__section'>
|
<div className='search-results__section'>
|
||||||
<h5><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></h5>
|
<h5><Icon id='users' fixedWidth /><FormattedMessage id='search_results.accounts' defaultMessage='Profiles' /></h5>
|
||||||
|
|
||||||
{results.get('accounts').map(accountId => <AccountContainer key={accountId} id={accountId} />)}
|
{results.get('accounts').map(accountId => <AccountContainer key={accountId} id={accountId} />)}
|
||||||
|
|
||||||
{results.get('accounts').size >= 5 && <LoadMore visible onClick={this.handleLoadMoreAccounts} />}
|
{showMore && <LoadMore visible onClick={this.handleLoadMoreAccounts} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (results.get('statuses') && results.get('statuses').size > 0) {
|
if (results.get('statuses') && results.get('statuses').size > 0) {
|
||||||
count += results.get('statuses').size;
|
count += results.get('statuses').size;
|
||||||
|
const showMore = this.showMoreResults('statuses');
|
||||||
statuses = (
|
statuses = (
|
||||||
<div className='search-results__section'>
|
<div className='search-results__section'>
|
||||||
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></h5>
|
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></h5>
|
||||||
|
|
||||||
{results.get('statuses').map(statusId => <StatusContainer key={statusId} id={statusId} />)}
|
{results.get('statuses').map(statusId => <StatusContainer key={statusId} id={statusId} />)}
|
||||||
|
|
||||||
{results.get('statuses').size >= 5 && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
|
{showMore && <LoadMore visible onClick={this.handleLoadMoreStatuses} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
|
} else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
|
||||||
|
@ -111,13 +116,14 @@ class SearchResults extends ImmutablePureComponent {
|
||||||
|
|
||||||
if (results.get('hashtags') && results.get('hashtags').size > 0) {
|
if (results.get('hashtags') && results.get('hashtags').size > 0) {
|
||||||
count += results.get('hashtags').size;
|
count += results.get('hashtags').size;
|
||||||
|
const showMore = this.showMoreResults('hashtags');
|
||||||
hashtags = (
|
hashtags = (
|
||||||
<div className='search-results__section'>
|
<div className='search-results__section'>
|
||||||
<h5><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5>
|
<h5><Icon id='hashtag' fixedWidth /><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></h5>
|
||||||
|
|
||||||
{results.get('hashtags').map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
|
{results.get('hashtags').map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
|
||||||
|
|
||||||
{results.get('hashtags').size >= 5 && <LoadMore visible onClick={this.handleLoadMoreHashtags} />}
|
{showMore && <LoadMore visible onClick={this.handleLoadMoreHashtags} />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ const initialState = ImmutableMap({
|
||||||
submitted: false,
|
submitted: false,
|
||||||
hidden: false,
|
hidden: false,
|
||||||
results: ImmutableMap(),
|
results: ImmutableMap(),
|
||||||
|
noMoreResults: ImmutableMap(),
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
searchTerm: '',
|
searchTerm: '',
|
||||||
recent: ImmutableOrderedSet(),
|
recent: ImmutableOrderedSet(),
|
||||||
|
@ -34,6 +35,7 @@ export default function search(state = initialState, action) {
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.set('value', '');
|
map.set('value', '');
|
||||||
map.set('results', ImmutableMap());
|
map.set('results', ImmutableMap());
|
||||||
|
map.set('noMoreResults', ImmutableMap());
|
||||||
map.set('submitted', false);
|
map.set('submitted', false);
|
||||||
map.set('hidden', false);
|
map.set('hidden', false);
|
||||||
});
|
});
|
||||||
|
@ -57,13 +59,18 @@ export default function search(state = initialState, action) {
|
||||||
statuses: ImmutableList(action.results.statuses.map(item => item.id)),
|
statuses: ImmutableList(action.results.statuses.map(item => item.id)),
|
||||||
hashtags: fromJS(action.results.hashtags),
|
hashtags: fromJS(action.results.hashtags),
|
||||||
}));
|
}));
|
||||||
|
map.set('noMoreResults', ImmutableMap({
|
||||||
|
accounts: action.results.accounts.length <= 0,
|
||||||
|
statuses: action.results.statuses.length <= 0,
|
||||||
|
hashtags: false,
|
||||||
|
}));
|
||||||
|
|
||||||
map.set('searchTerm', action.searchTerm);
|
map.set('searchTerm', action.searchTerm);
|
||||||
map.set('isLoading', false);
|
map.set('isLoading', false);
|
||||||
});
|
});
|
||||||
case SEARCH_EXPAND_SUCCESS:
|
case SEARCH_EXPAND_SUCCESS:
|
||||||
const results = action.searchType === 'hashtags' ? fromJS(action.results.hashtags) : action.results[action.searchType].map(item => item.id);
|
const results = action.searchType === 'hashtags' ? fromJS(action.results.hashtags) : action.results[action.searchType].map(item => item.id);
|
||||||
return state.updateIn(['results', action.searchType], list => list.concat(results));
|
return state.updateIn(['results', action.searchType], list => list.concat(results)).setIn(['noMoreResults', action.searchType], results.size <= 0);
|
||||||
case SEARCH_RESULT_CLICK:
|
case SEARCH_RESULT_CLICK:
|
||||||
return state.update('recent', set => set.add(fromJS(action.result)));
|
return state.update('recent', set => set.add(fromJS(action.result)));
|
||||||
case SEARCH_RESULT_FORGET:
|
case SEARCH_RESULT_FORGET:
|
||||||
|
|
|
@ -15,6 +15,12 @@ class StatusFilter
|
||||||
blocked_by_policy? || (account_present? && filtered_status?) || silenced_account?
|
blocked_by_policy? || (account_present? && filtered_status?) || silenced_account?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def search_filtered?
|
||||||
|
return false if !account.nil? && account.id == status.account_id
|
||||||
|
|
||||||
|
blocked_by_policy_search? || (account_present? && filtered_status?) || silenced_account?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def account_present?
|
def account_present?
|
||||||
|
@ -53,7 +59,15 @@ class StatusFilter
|
||||||
!policy_allows_show?
|
!policy_allows_show?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def blocked_by_policy_search?
|
||||||
|
!policy_allows_search?
|
||||||
|
end
|
||||||
|
|
||||||
def policy_allows_show?
|
def policy_allows_show?
|
||||||
StatusPolicy.new(account, status, @preloaded_relations).show?
|
StatusPolicy.new(account, status, @preloaded_relations).show?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def policy_allows_search?
|
||||||
|
StatusPolicy.new(account, status, @preloaded_relations).search?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -157,12 +157,14 @@ class Status < ApplicationRecord
|
||||||
if preloaded.nil?
|
if preloaded.nil?
|
||||||
ids += mentions.joins(:account).merge(Account.local).active.pluck(:account_id)
|
ids += mentions.joins(:account).merge(Account.local).active.pluck(:account_id)
|
||||||
ids += favourites.joins(:account).merge(Account.local).pluck(:account_id)
|
ids += favourites.joins(:account).merge(Account.local).pluck(:account_id)
|
||||||
|
ids += emoji_reactions.joins(:account).merge(Account.local).pluck(:account_id)
|
||||||
ids += reblogs.joins(:account).merge(Account.local).pluck(:account_id)
|
ids += reblogs.joins(:account).merge(Account.local).pluck(:account_id)
|
||||||
ids += bookmarks.joins(:account).merge(Account.local).pluck(:account_id)
|
ids += bookmarks.joins(:account).merge(Account.local).pluck(:account_id)
|
||||||
ids += poll.votes.joins(:account).merge(Account.local).pluck(:account_id) if poll.present?
|
ids += poll.votes.joins(:account).merge(Account.local).pluck(:account_id) if poll.present?
|
||||||
else
|
else
|
||||||
ids += preloaded.mentions[id] || []
|
ids += preloaded.mentions[id] || []
|
||||||
ids += preloaded.favourites[id] || []
|
ids += preloaded.favourites[id] || []
|
||||||
|
ids += preloaded.emoji_reactions[id] || []
|
||||||
ids += preloaded.reblogs[id] || []
|
ids += preloaded.reblogs[id] || []
|
||||||
ids += preloaded.bookmarks[id] || []
|
ids += preloaded.bookmarks[id] || []
|
||||||
ids += preloaded.votes[id] || []
|
ids += preloaded.votes[id] || []
|
||||||
|
|
|
@ -19,6 +19,18 @@ class StatusPolicy < ApplicationPolicy
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def search?
|
||||||
|
return false if author.suspended?
|
||||||
|
|
||||||
|
if requires_mention?
|
||||||
|
owned? || mention_exists?
|
||||||
|
elsif !public?
|
||||||
|
owned? || following_author? || mention_exists?
|
||||||
|
else
|
||||||
|
current_account.nil? || (!author_blocking? && !author_blocking_domain?)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def reblog?
|
def reblog?
|
||||||
!requires_mention? && (!private? || owned?) && show? && !blocking_author?
|
!requires_mention? && (!private? || owned?) && show? && !blocking_author?
|
||||||
end
|
end
|
||||||
|
@ -55,6 +67,10 @@ class StatusPolicy < ApplicationPolicy
|
||||||
record.private_visibility?
|
record.private_visibility?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def public?
|
||||||
|
record.public_visibility? || record.public_unlisted_visibility?
|
||||||
|
end
|
||||||
|
|
||||||
def mention_exists?
|
def mention_exists?
|
||||||
return false if current_account.nil?
|
return false if current_account.nil?
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,8 @@ class SearchService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_statuses_search!
|
def perform_statuses_search!
|
||||||
definition = parsed_query.apply(StatusesIndex.filter(term: { searchable_by: @account.id }))
|
# definition = parsed_query.apply(StatusesIndex.filter(term: { searchable_by: @account.id })).order(id: :desc)
|
||||||
|
definition = parsed_query.apply(StatusesIndex).order(id: :desc)
|
||||||
|
|
||||||
definition = definition.filter(term: { account_id: @options[:account_id] }) if @options[:account_id].present?
|
definition = definition.filter(term: { account_id: @options[:account_id] }) if @options[:account_id].present?
|
||||||
|
|
||||||
|
@ -51,7 +52,7 @@ class SearchService < BaseService
|
||||||
account_domains = results.map(&:account_domain)
|
account_domains = results.map(&:account_domain)
|
||||||
preloaded_relations = @account.relations_map(account_ids, account_domains)
|
preloaded_relations = @account.relations_map(account_ids, account_domains)
|
||||||
|
|
||||||
results.reject { |status| StatusFilter.new(status, @account, preloaded_relations).filtered? }
|
results.reject { |status| StatusFilter.new(status, @account, preloaded_relations).search_filtered? }
|
||||||
rescue Faraday::ConnectionFailed, Parslet::ParseFailed
|
rescue Faraday::ConnectionFailed, Parslet::ParseFailed
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue