From 74ae158c2f7b7d282ce1cc754ac83d27467a7215 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 15 Mar 2017 22:52:57 +0100 Subject: [PATCH] Add "direct" visibility level in the backend. Web UI is not yet adjusted to allow choosing it, yet --- .../components/status_action_bar.jsx | 2 +- .../features/status/components/action_bar.jsx | 2 +- app/lib/feed_manager.rb | 1 + app/models/status.rb | 27 +++++++++++-------- app/services/fan_out_on_write_service.rb | 13 ++++++++- app/services/reblog_service.rb | 2 +- 6 files changed, 32 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/components/components/status_action_bar.jsx b/app/assets/javascripts/components/components/status_action_bar.jsx index 469506f2f..234cd396a 100644 --- a/app/assets/javascripts/components/components/status_action_bar.jsx +++ b/app/assets/javascripts/components/components/status_action_bar.jsx @@ -88,7 +88,7 @@ const StatusActionBar = React.createClass({ return (
-
+
diff --git a/app/assets/javascripts/components/features/status/components/action_bar.jsx b/app/assets/javascripts/components/features/status/components/action_bar.jsx index 2acf94274..2aebcd709 100644 --- a/app/assets/javascripts/components/features/status/components/action_bar.jsx +++ b/app/assets/javascripts/components/features/status/components/action_bar.jsx @@ -74,7 +74,7 @@ const ActionBar = React.createClass({ return (
-
+
diff --git a/app/lib/feed_manager.rb b/app/lib/feed_manager.rb index 3a26c5c05..b0dda1256 100644 --- a/app/lib/feed_manager.rb +++ b/app/lib/feed_manager.rb @@ -108,6 +108,7 @@ class FeedManager elsif status.reblog? # Filter out a reblog should_filter = receiver.blocking?(status.reblog.account) # if I'm blocking the reblogged person should_filter ||= receiver.muting?(status.reblog.account) # or muting that person + should_filter ||= status.reblog.account.blocking?(receiver) # or if the author of the reblogged status is blocking me end should_filter ||= receiver.blocking?(status.mentions.map(&:account_id)) # or if it mentions someone I blocked diff --git a/app/models/status.rb b/app/models/status.rb index 663ac1e34..d5bbf70fb 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -6,7 +6,7 @@ class Status < ApplicationRecord include Streamable include Cacheable - enum visibility: [:public, :unlisted, :private], _suffix: :visibility + enum visibility: [:public, :unlisted, :private, :direct], _suffix: :visibility belongs_to :application, class_name: 'Doorkeeper::Application' @@ -75,12 +75,14 @@ class Status < ApplicationRecord end def hidden? - private_visibility? + private_visibility? || direct_visibility? end def permitted?(other_account = nil) - if private_visibility? - (account.id == other_account&.id || other_account&.following?(account) || mentions.where(account: other_account).exists?) + if direct_visibility? + account.id == other_account&.id || mentions.where(account: other_account).exists? + elsif private_visibility? + account.id == other_account&.id || other_account&.following?(account) || mentions.where(account: other_account).exists? else other_account.nil? || !account.blocking?(other_account) end @@ -156,15 +158,18 @@ class Status < ApplicationRecord end def permitted_for(target_account, account) - if account&.id == target_account.id || account&.following?(target_account) - where('1 = 1') - elsif !account.nil? && target_account.blocking?(account) + return where.not(visibility: [:private, :direct]) if account.nil? + + if target_account.blocking?(account) # get rid of blocked peeps where('1 = 0') - elsif !account.nil? + elsif account.id == target_account.id # author can see own stuff + where('1 = 1') + elsif account.following?(target_account) # followers can see followers-only stuff, but also things they are mentioned in + joins('LEFT OUTER JOIN mentions ON statuses.id = mentions.status_id AND mentions.account_id = ' + account.id.to_s) + .where('statuses.visibility != ? OR mentions.id IS NOT NULL', Status.visibilities[:direct]) + else # non-followers can see everything that isn't private/direct, but can see stuff they are mentioned in joins('LEFT OUTER JOIN mentions ON statuses.id = mentions.status_id AND mentions.account_id = ' + account.id.to_s) - .where('statuses.visibility != ? OR mentions.id IS NOT NULL', Status.visibilities[:private]) - else - where.not(visibility: :private) + .where('statuses.visibility NOT IN (?) OR mentions.id IS NOT NULL', [Status.visibilities[:direct], Status.visibilities[:private]]) end end diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb index 71f6cbca1..0cacfd7cd 100644 --- a/app/services/fan_out_on_write_service.rb +++ b/app/services/fan_out_on_write_service.rb @@ -5,7 +5,8 @@ class FanOutOnWriteService < BaseService # @param [Status] status def call(status) deliver_to_self(status) if status.account.local? - deliver_to_followers(status) + + status.direct_visibility? ? deliver_to_mentioned_followers(status) : deliver_to_followers(status) return if status.account.silenced? || !status.public_visibility? || status.reblog? @@ -32,6 +33,16 @@ class FanOutOnWriteService < BaseService end end + def deliver_to_mentioned_followers(status) + Rails.logger.debug "Delivering status #{status.id} to mentioned followers" + + status.mentions.includes(:account).each do |mention| + mentioned_account = mention.account + next if !mentioned_account.local? || !mentioned_account.following?(status.account) || FeedManager.instance.filter?(:home, status, mentioned_account) + FeedManager.instance.push(:home, mentioned_account, status) + end + end + def deliver_to_hashtags(status) Rails.logger.debug "Delivering status #{status.id} to hashtags" diff --git a/app/services/reblog_service.rb b/app/services/reblog_service.rb index c14b2925a..11446ce28 100644 --- a/app/services/reblog_service.rb +++ b/app/services/reblog_service.rb @@ -10,7 +10,7 @@ class ReblogService < BaseService def call(account, reblogged_status) reblogged_status = reblogged_status.reblog if reblogged_status.reblog? - raise Mastodon::NotPermittedError if reblogged_status.private_visibility? || !reblogged_status.permitted?(account) + raise Mastodon::NotPermittedError if reblogged_status.direct_visibility? || reblogged_status.private_visibility? || !reblogged_status.permitted?(account) reblog = account.statuses.create!(reblog: reblogged_status, text: '')