activitypub-academy/app/lib/feed_manager.rb
Eugen Rochko b891a81008 Follow call on locked account creates follow request instead
Reflect "requested" relationship in API and UI
Reflect inability of private posts to be reblogged in the UI
Disable Webfinger for locked accounts
2016-12-22 23:03:57 +01:00

119 lines
4 KiB
Ruby

# frozen_string_literal: true
require 'singleton'
class FeedManager
include Singleton
MAX_ITEMS = 800
def key(type, id)
"feed:#{type}:#{id}"
end
def filter?(timeline_type, status, receiver)
if timeline_type == :home
filter_from_home?(status, receiver)
elsif timeline_type == :mentions
filter_from_mentions?(status, receiver)
elsif timeline_type == :public
filter_from_public?(status, receiver)
else
false
end
end
def push(timeline_type, account, status)
redis.zadd(key(timeline_type, account.id), status.id, status.reblog? ? status.reblog_of_id : status.id)
trim(timeline_type, account.id)
broadcast(account.id, type: 'update', timeline: timeline_type, message: inline_render(account, 'api/v1/statuses/show', status))
end
def broadcast(timeline_id, options = {})
ActionCable.server.broadcast("timeline:#{timeline_id}", options)
end
def trim(type, account_id)
return unless redis.zcard(key(type, account_id)) > FeedManager::MAX_ITEMS
last = redis.zrevrange(key(type, account_id), FeedManager::MAX_ITEMS - 1, FeedManager::MAX_ITEMS - 1)
redis.zremrangebyscore(key(type, account_id), '-inf', "(#{last.last}")
end
def merge_into_timeline(from_account, into_account)
timeline_key = key(:home, into_account.id)
from_account.statuses.limit(MAX_ITEMS).each do |status|
redis.zadd(timeline_key, status.id, status.id)
end
trim(:home, into_account.id)
end
def inline_render(target_account, template, object)
rabl_scope = Class.new do
include RoutingHelper
def initialize(account)
@account = account
end
def current_user
@account.try(:user)
end
def current_account
@account
end
end
Rabl::Renderer.new(template, object, view_path: 'app/views', format: :json, scope: rabl_scope.new(target_account)).render
end
private
def redis
Redis.current
end
def filter_from_home?(status, receiver)
should_filter = false
if status.reply? && !status.thread.account.nil? # Filter out if it's a reply
should_filter = !receiver.following?(status.thread.account) # and I'm not following the person it's a reply to
should_filter &&= !(receiver.id == status.thread.account_id) # and it's not a reply to me
should_filter &&= !(status.account_id == status.thread.account_id) # and it's not a self-reply
elsif status.reblog? # Filter out a reblog
should_filter = receiver.blocking?(status.reblog.account) # if I'm blocking the reblogged person
end
should_filter ||= receiver.blocking?(status.mentions.map(&:account_id)) # or if it mentions someone I blocked
should_filter
end
def filter_from_mentions?(status, receiver)
should_filter = receiver.id == status.account_id # Filter if I'm mentioning myself
should_filter ||= receiver.blocking?(status.account) # or it's from someone I blocked
should_filter ||= receiver.blocking?(status.mentions.includes(:account).map(&:account)) # or if it mentions someone I blocked
should_filter ||= (status.account.silenced? && !receiver.following?(status.account)) # of if the account is silenced and I'm not following them
if status.reply? && !status.thread.account.nil? # or it's a reply
should_filter ||= receiver.blocking?(status.thread.account) # to a user I blocked
end
should_filter
end
def filter_from_public?(status, receiver)
should_filter = receiver.blocking?(status.account)
should_filter ||= receiver.blocking?(status.mentions.includes(:account).map(&:account))
if status.reply? && !status.thread.account.nil?
should_filter ||= receiver.blocking?(status.thread.account)
elsif status.reblog?
should_filter ||= receiver.blocking?(status.reblog.account)
end
should_filter
end
end