0
0
Fork 0

Add notifications of severed relationships (#27511)

This commit is contained in:
Claire 2024-03-20 16:37:21 +01:00 committed by GitHub
parent 8a1423a474
commit 44bf7b8128
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 781 additions and 54 deletions

View file

@ -0,0 +1,6 @@
# frozen_string_literal: true
Fabricator(:account_relationship_severance_event) do
account
relationship_severance_event
end

View file

@ -0,0 +1,6 @@
# frozen_string_literal: true
Fabricator(:relationship_severance_event) do
type { :domain_block }
target_name { 'example.com' }
end

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
Fabricator(:severed_relationship) do
local_account { Fabricate.build(:account) }
remote_account { Fabricate.build(:account) }
relationship_severance_event { Fabricate.build(:relationship_severance_event) }
direction { :active }
end

View file

@ -0,0 +1,49 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe RelationshipSeveranceEvent do
let(:local_account) { Fabricate(:account) }
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
let(:event) { Fabricate(:relationship_severance_event) }
describe '#import_from_active_follows!' do
before do
local_account.follow!(remote_account)
end
it 'imports the follow relationships with the expected direction' do
event.import_from_active_follows!(local_account.active_relationships)
relationships = event.severed_relationships.to_a
expect(relationships.size).to eq 1
expect(relationships[0].account).to eq local_account
expect(relationships[0].target_account).to eq remote_account
end
end
describe '#import_from_passive_follows!' do
before do
remote_account.follow!(local_account)
end
it 'imports the follow relationships with the expected direction' do
event.import_from_passive_follows!(local_account.passive_relationships)
relationships = event.severed_relationships.to_a
expect(relationships.size).to eq 1
expect(relationships[0].account).to eq remote_account
expect(relationships[0].target_account).to eq local_account
end
end
describe '#affected_local_accounts' do
before do
event.severed_relationships.create!(local_account: local_account, remote_account: remote_account, direction: :active)
end
it 'correctly lists local accounts' do
expect(event.affected_local_accounts.to_a).to contain_exactly(local_account)
end
end
end

View file

@ -0,0 +1,45 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe SeveredRelationship do
let(:local_account) { Fabricate(:account) }
let(:remote_account) { Fabricate(:account, domain: 'example.com') }
let(:event) { Fabricate(:relationship_severance_event) }
describe '#account' do
context 'when the local account is the follower' do
let(:severed_relationship) { Fabricate(:severed_relationship, relationship_severance_event: event, local_account: local_account, remote_account: remote_account, direction: :active) }
it 'returns the local account' do
expect(severed_relationship.account).to eq local_account
end
end
context 'when the local account is being followed' do
let(:severed_relationship) { Fabricate(:severed_relationship, relationship_severance_event: event, local_account: local_account, remote_account: remote_account, direction: :passive) }
it 'returns the remote account' do
expect(severed_relationship.account).to eq remote_account
end
end
end
describe '#target_account' do
context 'when the local account is the follower' do
let(:severed_relationship) { Fabricate(:severed_relationship, relationship_severance_event: event, local_account: local_account, remote_account: remote_account, direction: :active) }
it 'returns the remote account' do
expect(severed_relationship.target_account).to eq remote_account
end
end
context 'when the local account is being followed' do
let(:severed_relationship) { Fabricate(:severed_relationship, relationship_severance_event: event, local_account: local_account, remote_account: remote_account, direction: :passive) }
it 'returns the local account' do
expect(severed_relationship.target_account).to eq local_account
end
end
end
end

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
require 'rails_helper'
describe 'Severed relationships page' do
include RoutingHelper
describe 'GET severed_relationships#index' do
let(:user) { Fabricate(:user) }
before do
sign_in user
Fabricate(:severed_relationship, local_account: user.account)
end
it 'returns http success' do
get severed_relationships_path
expect(response).to have_http_status(200)
end
end
end

View file

@ -5,22 +5,33 @@ require 'rails_helper'
RSpec.describe AfterBlockDomainFromAccountService do
subject { described_class.new }
let!(:wolf) { Fabricate(:account, username: 'wolf', domain: 'evil.org', inbox_url: 'https://evil.org/inbox', protocol: :activitypub) }
let!(:alice) { Fabricate(:account, username: 'alice') }
let(:wolf) { Fabricate(:account, username: 'wolf', domain: 'evil.org', inbox_url: 'https://evil.org/wolf/inbox', protocol: :activitypub) }
let(:dog) { Fabricate(:account, username: 'dog', domain: 'evil.org', inbox_url: 'https://evil.org/dog/inbox', protocol: :activitypub) }
let(:alice) { Fabricate(:account, username: 'alice') }
before do
allow(ActivityPub::DeliveryWorker).to receive(:perform_async)
wolf.follow!(alice)
alice.follow!(dog)
end
it 'purge followers from blocked domain' do
wolf.follow!(alice)
around do |example|
Sidekiq::Testing.fake! do
example.run
end
end
it 'purges followers from blocked domain, sends them Reject->Follow, and records severed relationships', :aggregate_failures do
subject.call(alice, 'evil.org')
expect(wolf.following?(alice)).to be false
end
expect(ActivityPub::DeliveryWorker.jobs.pluck('args')).to contain_exactly(
[a_string_including('"type":"Reject"'), alice.id, wolf.inbox_url],
[a_string_including('"type":"Undo"'), alice.id, dog.inbox_url]
)
it 'sends Reject->Follow to followers from blocked domain' do
wolf.follow!(alice)
subject.call(alice, 'evil.org')
expect(ActivityPub::DeliveryWorker).to have_received(:perform_async).once
severed_relationships = alice.severed_relationships.to_a
expect(severed_relationships.count).to eq 2
expect(severed_relationships[0].relationship_severance_event).to eq severed_relationships[1].relationship_severance_event
expect(severed_relationships.map { |rel| [rel.account, rel.target_account] }).to contain_exactly([wolf, alice], [alice, dog])
end
end

View file

@ -5,6 +5,8 @@ require 'rails_helper'
RSpec.describe BlockDomainService do
subject { described_class.new }
let(:local_account) { Fabricate(:account) }
let(:bystander) { Fabricate(:account, domain: 'evil.org') }
let!(:bad_account) { Fabricate(:account, username: 'badguy666', domain: 'evil.org') }
let!(:bad_status_plain) { Fabricate(:status, account: bad_account, text: 'You suck') }
let!(:bad_status_with_attachment) { Fabricate(:status, account: bad_account, text: 'Hahaha') }
@ -13,62 +15,51 @@ RSpec.describe BlockDomainService do
describe 'for a suspension' do
before do
local_account.follow!(bad_account)
bystander.follow!(local_account)
end
it 'creates a domain block, suspends remote accounts with appropriate suspension date, records severed relationships', :aggregate_failures do
subject.call(DomainBlock.create!(domain: 'evil.org', severity: :suspend))
end
it 'creates a domain block' do
expect(DomainBlock.blocked?('evil.org')).to be true
end
it 'removes remote accounts from that domain' do
# Suspends account with appropriate suspension date
expect(bad_account.reload.suspended?).to be true
end
it 'records suspension date appropriately' do
expect(bad_account.reload.suspended_at).to eq DomainBlock.find_by(domain: 'evil.org').created_at
end
it 'keeps already-banned accounts banned' do
# Keep already-suspended account without updating the suspension date
expect(already_banned_account.reload.suspended?).to be true
end
it 'does not overwrite suspension date of already-banned accounts' do
expect(already_banned_account.reload.suspended_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at
end
it 'removes the remote accounts\'s statuses and media attachments' do
# Removes content
expect { bad_status_plain.reload }.to raise_exception ActiveRecord::RecordNotFound
expect { bad_status_with_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound
expect { bad_attachment.reload }.to raise_exception ActiveRecord::RecordNotFound
# Records severed relationships
severed_relationships = local_account.severed_relationships.to_a
expect(severed_relationships.count).to eq 2
expect(severed_relationships[0].relationship_severance_event).to eq severed_relationships[1].relationship_severance_event
expect(severed_relationships.map { |rel| [rel.account, rel.target_account] }).to contain_exactly([bystander, local_account], [local_account, bad_account])
end
end
describe 'for a silence with reject media' do
before do
it 'does not mark the domain as blocked, but silences accounts with an appropriate silencing date, clears media', :aggregate_failures, :sidekiq_inline do
subject.call(DomainBlock.create!(domain: 'evil.org', severity: :silence, reject_media: true))
end
it 'does not create a domain block' do
expect(DomainBlock.blocked?('evil.org')).to be false
end
it 'silences remote accounts from that domain' do
# Silences account with appropriate silecing date
expect(bad_account.reload.silenced?).to be true
end
it 'records suspension date appropriately' do
expect(bad_account.reload.silenced_at).to eq DomainBlock.find_by(domain: 'evil.org').created_at
end
it 'keeps already-banned accounts banned' do
# Keeps already-silenced accounts without updating the silecing date
expect(already_banned_account.reload.silenced?).to be true
end
it 'does not overwrite suspension date of already-banned accounts' do
expect(already_banned_account.reload.silenced_at).to_not eq DomainBlock.find_by(domain: 'evil.org').created_at
end
it 'leaves the domains status and attachments, but clears media', :sidekiq_inline do
# Leaves posts but clears media
expect { bad_status_plain.reload }.to_not raise_error
expect { bad_status_with_attachment.reload }.to_not raise_error
expect { bad_attachment.reload }.to_not raise_error

View file

@ -59,7 +59,7 @@ RSpec.describe SuspendAccountService, :sidekiq_inline do
remote_follower.follow!(account)
end
it 'sends an update actor to followers and reporters' do
it 'sends an Update actor activity to followers and reporters' do
subject
expect(a_request(:post, remote_follower.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once
expect(a_request(:post, remote_reporter.inbox_url).with { |req| match_update_actor_request(req, account) }).to have_been_made.once
@ -85,9 +85,14 @@ RSpec.describe SuspendAccountService, :sidekiq_inline do
account.follow!(local_followee)
end
it 'sends a reject follow' do
it 'sends a Reject Follow activity, and records severed relationships', :aggregate_failures do
subject
expect(a_request(:post, account.inbox_url).with { |req| match_reject_follow_request(req, account, local_followee) }).to have_been_made.once
severed_relationships = local_followee.severed_relationships.to_a
expect(severed_relationships.count).to eq 1
expect(severed_relationships.map { |rel| [rel.account, rel.target_account] }).to contain_exactly([account, local_followee])
end
end
end