Add service to revoke inclusion in a Collection (#38026)

This commit is contained in:
David Roetzel 2026-03-02 11:16:41 +01:00 committed by GitHub
parent 6ab24de659
commit 2f65701920
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 105 additions and 0 deletions

View File

@ -42,6 +42,10 @@ class CollectionItem < ApplicationRecord
scope :not_blocked_by, ->(account) { where.not(accounts: { id: account.blocking }) }
scope :local, -> { joins(:collection).merge(Collection.local) }
def revoke!
update!(state: :revoked)
end
def local_item_with_remote_account?
local? && account&.remote?
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class ActivityPub::DeleteFeatureAuthorizationSerializer < ActivityPub::Serializer
include RoutingHelper
attributes :id, :type, :actor, :to
has_one :object, serializer: ActivityPub::FeatureAuthorizationSerializer
def id
[ap_account_feature_authorization_url(object.account_id, object), '#delete'].join
end
def type
'Delete'
end
def actor
ActivityPub::TagManager.instance.uri_for(object.account)
end
def to
[ActivityPub::TagManager::COLLECTIONS[:public]]
end
end

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
class RevokeCollectionItemService < BaseService
include Payloadable
def call(collection_item)
@collection_item = collection_item
@account = collection_item.account
@collection_item.revoke!
distribute_stamp_deletion! if Mastodon::Feature.collections_federation_enabled? && @collection_item.remote?
end
private
def distribute_stamp_deletion!
ActivityPub::AccountRawDistributionWorker.perform_async(signed_activity_json, @collection_item.collection.account_id)
end
def signed_activity_json
@signed_activity_json ||= Oj.dump(serialize_payload(@collection_item, ActivityPub::DeleteFeatureAuthorizationSerializer, signer: @account, always_sign: true))
end
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe ActivityPub::DeleteFeatureAuthorizationSerializer do
include RoutingHelper
subject { serialized_record_json(collection_item, described_class, adapter: ActivityPub::Adapter) }
describe 'serializing an object' do
let(:collection) { Fabricate(:remote_collection) }
let(:collection_item) { Fabricate(:collection_item, collection:, uri: 'https://example.com') }
it 'returns expected json structure' do
expect(subject)
.to include({
'type' => 'Delete',
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
'actor' => ActivityPub::TagManager.instance.uri_for(collection_item.account),
'object' => a_hash_including({
'type' => 'FeatureAuthorization',
'id' => ap_account_feature_authorization_url(collection_item.account_id, collection_item),
}),
})
end
end
end

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe RevokeCollectionItemService do
subject { described_class.new }
let(:collection_item) { Fabricate(:collection_item) }
it 'revokes the collection item and sends a Delete activity' do
expect { subject.call(collection_item) }
.to change { collection_item.reload.state }.from('accepted').to('revoked')
end
context 'when the collection is remote', feature: :collections_federation do
let(:collection) { Fabricate(:remote_collection) }
let(:collection_item) { Fabricate(:collection_item, collection:, uri: 'https://example.com') }
it 'federates a `Delete` activity' do
subject.call(collection_item)
expect(ActivityPub::AccountRawDistributionWorker).to have_enqueued_sidekiq_job
end
end
end