end
def direct_statuses
- direct_timeline_statuses.paginate_by_max_id(
- limit_param(DEFAULT_STATUSES_LIMIT),
- params[:max_id],
- params[:since_id]
- )
+ direct_timeline_statuses
end
def direct_timeline_statuses
- Status.as_direct_timeline(current_account)
+ # this query requires built in pagination.
+ Status.as_direct_timeline(
+ current_account,
+ limit_param(DEFAULT_STATUSES_LIMIT),
+ params[:max_id],
+ params[:since_id],
+ true # returns array of cache_ids object
+ )
end
def insert_pagination_headers
where(account: [account] + account.following).where(visibility: [:public, :unlisted, :private])
end
- def as_direct_timeline(account)
- query = joins("LEFT OUTER JOIN mentions ON statuses.id = mentions.status_id AND mentions.account_id = #{account.id}")
- .where("mentions.account_id = #{account.id} OR statuses.account_id = #{account.id}")
- .where(visibility: [:direct])
+ def as_direct_timeline(account, limit = 20, max_id = nil, since_id = nil, cache_ids = false)
+ # direct timeline is mix of direct message from_me and to_me.
+ # 2 querys are executed with pagination.
+ # constant expression using arel_table is required for partial index
+
+ # _from_me part does not require any timeline filters
+ query_from_me = where(account_id: account.id)
+ .where(Status.arel_table[:visibility].eq(3))
+ .limit(limit)
+ .order('statuses.id DESC')
+
+ # _to_me part requires mute and block filter.
+ # FIXME: may we check mutes.hide_notifications?
+ query_to_me = Status
+ .joins(:mentions)
+ .merge(Mention.where(account_id: account.id))
+ .where(Status.arel_table[:visibility].eq(3))
+ .limit(limit)
+ .order('mentions.status_id DESC')
+ .not_excluded_by_account(account)
+
+ if max_id.present?
+ query_from_me = query_from_me.where('statuses.id < ?', max_id)
+ query_to_me = query_to_me.where('mentions.status_id < ?', max_id)
+ end
+
+ if since_id.present?
+ query_from_me = query_from_me.where('statuses.id > ?', since_id)
+ query_to_me = query_to_me.where('mentions.status_id > ?', since_id)
+ end
- apply_timeline_filters(query, account, false)
+ if cache_ids
+ # returns array of cache_ids object that have id and updated_at
+ (query_from_me.cache_ids.to_a + query_to_me.cache_ids.to_a).uniq(&:id).sort_by(&:id).reverse.take(limit)
+ else
+ # returns ActiveRecord.Relation
+ items = (query_from_me.select(:id).to_a + query_to_me.select(:id).to_a).uniq(&:id).sort_by(&:id).reverse.take(limit)
+ Status.where(id: items.map(&:id))
+ end
end
def as_public_timeline(account = nil, local_only = false)
describe '#target' do
it 'returns nil if the status is self-contained' do
- expect(subject.target).to be_nil
+ expect(subject.target).to be_nil
end
it 'returns nil if the status is a reply' do
expect(@results).to_not include(@followed_public_status)
end
- it 'includes direct statuses mentioning recipient from followed' do
- Fabricate(:mention, account: account, status: @followed_direct_status)
- expect(@results).to include(@followed_direct_status)
- end
-
it 'does not include direct statuses not mentioning recipient from followed' do
expect(@results).to_not include(@followed_direct_status)
end
- it 'includes direct statuses mentioning recipient from non-followed' do
- Fabricate(:mention, account: account, status: @not_followed_direct_status)
- expect(@results).to include(@not_followed_direct_status)
- end
-
it 'does not include direct statuses not mentioning recipient from non-followed' do
expect(@results).to_not include(@not_followed_direct_status)
end
+ it 'includes direct statuses mentioning recipient from followed' do
+ Fabricate(:mention, account: account, status: @followed_direct_status)
+ results2 = Status.as_direct_timeline(account)
+ expect(results2).to include(@followed_direct_status)
+ end
+
+ it 'includes direct statuses mentioning recipient from non-followed' do
+ Fabricate(:mention, account: account, status: @not_followed_direct_status)
+ results2 = Status.as_direct_timeline(account)
+ expect(results2).to include(@not_followed_direct_status)
+ end
end
describe '.as_public_timeline' do