Add block from bot follow settings
This commit is contained in:
parent
214092b517
commit
ff994d78fa
12 changed files with 208 additions and 13 deletions
|
@ -36,7 +36,7 @@ class Api::V1::AccountsController < Api::BaseController
|
|||
|
||||
def follow
|
||||
follow = FollowService.new.call(current_user.account, @account, reblogs: params.key?(:reblogs) ? truthy_param?(:reblogs) : nil, notify: params.key?(:notify) ? truthy_param?(:notify) : nil, languages: params.key?(:languages) ? params[:languages] : nil, with_rate_limit: true)
|
||||
options = @account.locked? || current_user.account.silenced? ? {} : { following_map: { @account.id => { reblogs: follow.show_reblogs?, notify: follow.notify?, languages: follow.languages } }, requested_map: { @account.id => false } }
|
||||
options = @account.locked? || current_user.account.silenced? || (current_user.account.bot? && @account.user&.setting_lock_follow_from_bot) ? {} : { following_map: { @account.id => { reblogs: follow.show_reblogs?, notify: follow.notify?, languages: follow.languages } }, requested_map: { @account.id => false } }
|
||||
|
||||
render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships(**options)
|
||||
end
|
||||
|
|
|
@ -30,7 +30,7 @@ class ActivityPub::Activity::Follow < ActivityPub::Activity
|
|||
|
||||
follow_request = FollowRequest.create!(account: @account, target_account: target_account, uri: @json['id'])
|
||||
|
||||
if target_account.locked? || @account.silenced? || block_straight_follow?
|
||||
if target_account.locked? || @account.silenced? || block_straight_follow? || (@account.bot? && target_account.user&.setting_lock_follow_from_bot)
|
||||
LocalNotificationWorker.perform_async(target_account.id, follow_request.id, 'FollowRequest', 'follow_request')
|
||||
else
|
||||
AuthorizeFollowService.new.call(@account, target_account)
|
||||
|
|
|
@ -30,9 +30,9 @@ class StatusReachFinder
|
|||
if @status.reblog?
|
||||
[]
|
||||
elsif @status.limited_visibility?
|
||||
Account.where(id: mentioned_account_ids).where.not(domain: banned_domains).inboxes
|
||||
expect_bot_query(Account.where(id: mentioned_account_ids).where.not(domain: banned_domains)).inboxes
|
||||
else
|
||||
Account.where(id: reached_account_ids).where.not(domain: banned_domains).inboxes
|
||||
expect_bot_query(Account.where(id: reached_account_ids).where.not(domain: banned_domains)).inboxes
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -40,9 +40,9 @@ class StatusReachFinder
|
|||
if @status.reblog?
|
||||
[]
|
||||
elsif @status.limited_visibility?
|
||||
Account.where(id: mentioned_account_ids).where(domain: banned_domains_for_misskey).inboxes
|
||||
expect_bot_query(Account.where(id: mentioned_account_ids).where(domain: banned_domains_for_misskey)).inboxes
|
||||
else
|
||||
Account.where(id: reached_account_ids).where(domain: banned_domains_for_misskey).inboxes
|
||||
expect_bot_query(Account.where(id: reached_account_ids).where(domain: banned_domains_for_misskey)).inboxes
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -90,21 +90,25 @@ class StatusReachFinder
|
|||
|
||||
def followers_inboxes
|
||||
if @status.in_reply_to_local_account? && distributable?
|
||||
@status.account.followers.or(@status.thread.account.followers.not_domain_blocked_by_account(@status.account)).where.not(domain: banned_domains).inboxes
|
||||
scope = @status.account.followers.or(@status.thread.account.followers.not_domain_blocked_by_account(@status.account)).where.not(domain: banned_domains)
|
||||
expect_bot_query(scope).inboxes
|
||||
elsif @status.direct_visibility? || @status.limited_visibility?
|
||||
[]
|
||||
else
|
||||
@status.account.followers.where.not(domain: banned_domains).inboxes
|
||||
scope = @status.account.followers.where.not(domain: banned_domains)
|
||||
expect_bot_query(scope).inboxes
|
||||
end
|
||||
end
|
||||
|
||||
def followers_inboxes_for_misskey
|
||||
if @status.in_reply_to_local_account? && distributable?
|
||||
@status.account.followers.or(@status.thread.account.followers.not_domain_blocked_by_account(@status.account)).where(domain: banned_domains_for_misskey).inboxes
|
||||
scope = @status.account.followers.or(@status.thread.account.followers.not_domain_blocked_by_account(@status.account)).where(domain: banned_domains_for_misskey)
|
||||
expect_bot_query(scope).inboxes
|
||||
elsif @status.direct_visibility? || @status.limited_visibility?
|
||||
[]
|
||||
else
|
||||
@status.account.followers.where(domain: banned_domains_for_misskey).inboxes
|
||||
scope = @status.account.followers.where(domain: banned_domains_for_misskey)
|
||||
expect_bot_query(scope).inboxes
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -163,4 +167,12 @@ class StatusReachFinder
|
|||
from_domain_block = DomainBlock.where(detect_invalid_subscription: true).pluck(:domain)
|
||||
(from_info + from_domain_block).uniq
|
||||
end
|
||||
|
||||
def expect_bot_query(scope)
|
||||
if @status.account.user&.setting_stop_deliver_to_bot
|
||||
scope.where('actor_type NOT IN (\'Application\', \'Service\') OR accounts.id IN (?)', (@status.mentioned_accounts.pluck(:id) + [@status.in_reply_to_account_id]).compact)
|
||||
else
|
||||
scope
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -235,6 +235,14 @@ module HasUserSettings
|
|||
settings['disallow_unlisted_public_searchability']
|
||||
end
|
||||
|
||||
def setting_lock_follow_from_bot
|
||||
settings['lock_follow_from_bot']
|
||||
end
|
||||
|
||||
def setting_stop_deliver_to_bot
|
||||
settings['stop_deliver_to_bot']
|
||||
end
|
||||
|
||||
def allows_report_emails?
|
||||
settings['notification_emails.report']
|
||||
end
|
||||
|
|
|
@ -40,6 +40,8 @@ class UserSettings
|
|||
setting :unsafe_limited_distribution, default: false
|
||||
setting :dtl_force_with_tag, default: :none, in: %w(full searchability none)
|
||||
setting :dtl_force_subscribable, default: false
|
||||
setting :lock_follow_from_bot, default: false
|
||||
setting :stop_deliver_to_bot, default: false
|
||||
|
||||
setting_inverse_alias :indexable, :noindex
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class FollowService < BaseService
|
|||
# and the feeds are being merged
|
||||
mark_home_feed_as_partial! if @source_account.not_following_anyone?
|
||||
|
||||
if (@target_account.locked? && !@options[:bypass_locked]) || @source_account.silenced? || @target_account.activitypub?
|
||||
if (@target_account.locked? && !@options[:bypass_locked]) || @source_account.silenced? || @target_account.activitypub? || (@source_account.bot? && @target_account.user&.setting_lock_follow_from_bot)
|
||||
request_follow!
|
||||
elsif @target_account.local?
|
||||
direct_follow!
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
.fields-group
|
||||
= ff.input :aggregate_reblogs, wrapper: :with_label, recommended: true, label: I18n.t('simple_form.labels.defaults.setting_aggregate_reblogs'), hint: I18n.t('simple_form.hints.defaults.setting_aggregate_reblogs')
|
||||
|
||||
.fields-group
|
||||
= ff.input :lock_follow_from_bot, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_lock_follow_from_bot')
|
||||
|
||||
.fields-group
|
||||
= ff.input :stop_deliver_to_bot, wrapper: :with_label, kmyblue: true, label: I18n.t('simple_form.labels.defaults.setting_stop_deliver_to_bot')
|
||||
|
||||
%h4= t 'preferences.posting_defaults'
|
||||
|
||||
.fields-row
|
||||
|
|
|
@ -262,6 +262,7 @@ en:
|
|||
setting_hide_recent_emojis: Hide recent emojis
|
||||
setting_hide_statuses_count: Hide statuses count
|
||||
setting_link_preview: Generate post link preview card
|
||||
setting_lock_follow_from_bot: Request approval about bot follow
|
||||
setting_noai: Set noai meta tags
|
||||
setting_public_post_to_unlisted: Convert public post to public unlisted if not using Web app
|
||||
setting_reduce_motion: Reduce motion in animations
|
||||
|
@ -272,6 +273,7 @@ en:
|
|||
setting_show_emoji_reaction_on_timeline: Show all stamps on timeline
|
||||
setting_simple_timeline_menu: Reduce post menu on timeline
|
||||
setting_stay_privacy: Not change privacy after post
|
||||
setting_stop_deliver_to_bot: Stop delivering servers only bots follow you
|
||||
setting_stop_emoji_reaction_streaming: Disable stamp streamings
|
||||
setting_system_font_ui: Use system's default font
|
||||
setting_theme: Site theme
|
||||
|
|
|
@ -276,7 +276,9 @@ ja:
|
|||
setting_hide_recent_emojis: 絵文字ピッカーで最近使用した絵文字を隠す(リアクションデッキのみを表示する)
|
||||
setting_hide_statuses_count: 投稿数を隠す
|
||||
setting_link_preview: リンクのプレビューを生成する
|
||||
setting_lock_follow_from_bot: botからのフォローを承認制にする
|
||||
setting_stay_privacy: 投稿時に公開範囲を保存する
|
||||
setting_stop_deliver_to_bot: フォロワーがbotしかいないサーバーへメンション以外の投稿の配送を行わない
|
||||
setting_noai: 自分のコンテンツのAI学習利用に対して不快感を表明する
|
||||
setting_public_post_to_unlisted: サードパーティから公開範囲「公開」で投稿した場合、「ローカル公開」に変更する
|
||||
setting_reduce_motion: アニメーションの動きを減らす
|
||||
|
|
|
@ -49,10 +49,16 @@ RSpec.describe Api::V1::AccountsController do
|
|||
|
||||
describe 'POST #follow' do
|
||||
let(:scopes) { 'write:follows' }
|
||||
let(:my_actor_type) { 'Person' }
|
||||
let(:lock_follow_from_bot) { false }
|
||||
let(:other_account) { Fabricate(:account, username: 'bob', locked: locked) }
|
||||
|
||||
context 'when posting to an other account' do
|
||||
before do
|
||||
other_account.user.settings['lock_follow_from_bot'] = lock_follow_from_bot
|
||||
other_account.user.save!
|
||||
user.account.update!(actor_type: my_actor_type)
|
||||
|
||||
post :follow, params: { id: other_account.id }
|
||||
end
|
||||
|
||||
|
@ -97,6 +103,29 @@ RSpec.describe Api::V1::AccountsController do
|
|||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
|
||||
context 'with unlocked account from bot' do
|
||||
let(:locked) { false }
|
||||
let(:lock_follow_from_bot) { true }
|
||||
let(:my_actor_type) { 'Service' }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns JSON with following=false and requested=true' do
|
||||
json = body_as_json
|
||||
|
||||
expect(json[:following]).to be false
|
||||
expect(json[:requested]).to be true
|
||||
end
|
||||
|
||||
it 'creates a follow request relation between user and target user' do
|
||||
expect(user.account.requested?(other_account)).to be true
|
||||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'read:accounts'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when modifying follow options' do
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ActivityPub::Activity::Follow do
|
||||
let(:sender) { Fabricate(:account, domain: 'example.com', inbox_url: 'https://example.com/inbox') }
|
||||
let(:actor_type) { 'Person' }
|
||||
let(:sender) { Fabricate(:account, domain: 'example.com', inbox_url: 'https://example.com/inbox', actor_type: actor_type) }
|
||||
let(:recipient) { Fabricate(:account) }
|
||||
|
||||
let(:json) do
|
||||
|
@ -83,6 +84,25 @@ RSpec.describe ActivityPub::Activity::Follow do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when unlocked account but locked from bot' do
|
||||
let(:actor_type) { 'Service' }
|
||||
|
||||
before do
|
||||
recipient.user.settings['lock_follow_from_bot'] = true
|
||||
recipient.user.save!
|
||||
subject.perform
|
||||
end
|
||||
|
||||
it 'does not create a follow from sender to recipient' do
|
||||
expect(sender.following?(recipient)).to be false
|
||||
end
|
||||
|
||||
it 'creates a follow request' do
|
||||
expect(sender.requested?(recipient)).to be true
|
||||
expect(sender.follow_requests.find_by(target_account: recipient).uri).to eq 'foo'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when domain block reject_straight_follow' do
|
||||
before do
|
||||
Fabricate(:domain_block, domain: 'example.com', reject_straight_follow: true)
|
||||
|
|
|
@ -8,9 +8,10 @@ describe StatusReachFinder do
|
|||
subject { described_class.new(status) }
|
||||
|
||||
let(:parent_status) { nil }
|
||||
let(:in_reply_to_account_id) { nil }
|
||||
let(:visibility) { :public }
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let(:status) { Fabricate(:status, account: alice, thread: parent_status, visibility: visibility) }
|
||||
let(:status) { Fabricate(:status, account: alice, thread: parent_status, in_reply_to_account_id: in_reply_to_account_id, visibility: visibility) }
|
||||
|
||||
context 'with a simple case' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox') }
|
||||
|
@ -32,6 +33,119 @@ describe StatusReachFinder do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with locking bot' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox', actor_type: 'Service') }
|
||||
|
||||
context 'with follower' do
|
||||
before do
|
||||
alice.user.settings['stop_deliver_to_bot'] = true
|
||||
alice.user.save!
|
||||
bob.follow!(alice)
|
||||
end
|
||||
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with non-follower' do
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with locking bot from misskey' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox', actor_type: 'Service') }
|
||||
|
||||
context 'with follower' do
|
||||
before do
|
||||
Fabricate(:instance_info, domain: 'foo.bar', software: 'misskey')
|
||||
alice.user.settings['stop_deliver_to_bot'] = true
|
||||
alice.user.save!
|
||||
bob.follow!(alice)
|
||||
end
|
||||
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
|
||||
expect(subject.inboxes_for_misskey).to_not include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with non-follower' do
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
|
||||
expect(subject.inboxes_for_misskey).to_not include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with bot but not locking' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox', actor_type: 'Service') }
|
||||
|
||||
context 'with follower' do
|
||||
before do
|
||||
bob.follow!(alice)
|
||||
end
|
||||
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with non-follower' do
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to_not include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with bot but mention' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox', actor_type: 'Service') }
|
||||
let(:in_reply_to_account_id) { bob.id }
|
||||
|
||||
context 'with follower' do
|
||||
before do
|
||||
alice.user.settings['stop_deliver_to_bot'] = true
|
||||
alice.user.save!
|
||||
bob.follow!(alice)
|
||||
end
|
||||
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with non-follower' do
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with bot but mention to status' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox', actor_type: 'Service') }
|
||||
let(:parent_status) { Fabricate(:status, account: bob) }
|
||||
|
||||
context 'with follower' do
|
||||
before do
|
||||
alice.user.settings['stop_deliver_to_bot'] = true
|
||||
alice.user.save!
|
||||
bob.follow!(alice)
|
||||
end
|
||||
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
|
||||
context 'with non-follower' do
|
||||
it 'send status' do
|
||||
expect(subject.inboxes).to include 'https://foo.bar/inbox'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when misskey case with unlisted post' do
|
||||
let(:bob) { Fabricate(:account, username: 'bob', domain: 'foo.bar', protocol: :activitypub, inbox_url: 'https://foo.bar/inbox') }
|
||||
let(:sender_software) { 'mastodon' }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue