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 2acf942743..2aebcd7098 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 3a26c5c056..b0dda12564 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 663ac1e34d..d5bbf70fb6 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[:private])
- else
- where.not(visibility: :private)
+ .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 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 71f6cbca1c..0cacfd7cd3 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 c14b2925ac..11446ce28b 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: '')