Federate updates to collections (#37790)
This commit is contained in:
parent
0763ad0d96
commit
03f73377d9
@ -51,7 +51,7 @@ class Api::V1Alpha::CollectionsController < Api::BaseController
|
|||||||
def update
|
def update
|
||||||
authorize @collection, :update?
|
authorize @collection, :update?
|
||||||
|
|
||||||
@collection.update!(collection_update_params) # TODO: Create a service for this to federate changes
|
UpdateCollectionService.new.call(@collection, collection_update_params)
|
||||||
|
|
||||||
render json: @collection, serializer: REST::CollectionSerializer, adapter: :json
|
render json: @collection, serializer: REST::CollectionSerializer, adapter: :json
|
||||||
end
|
end
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ActivityPub::UpdateFeaturedCollectionSerializer < ActivityPub::Serializer
|
||||||
|
attributes :id, :type, :actor, :to
|
||||||
|
|
||||||
|
has_one :object, serializer: ActivityPub::FeaturedCollectionSerializer
|
||||||
|
|
||||||
|
def id
|
||||||
|
[ActivityPub::TagManager.instance.uri_for(object), '#updates/', object.updated_at.to_i].join
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
'Update'
|
||||||
|
end
|
||||||
|
|
||||||
|
def actor
|
||||||
|
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to
|
||||||
|
[ActivityPub::TagManager::COLLECTIONS[:public]]
|
||||||
|
end
|
||||||
|
end
|
||||||
28
app/services/update_collection_service.rb
Normal file
28
app/services/update_collection_service.rb
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class UpdateCollectionService
|
||||||
|
UPDATEABLE_PARAMS = %w(name description language sensitive discoverable tag_id).freeze
|
||||||
|
|
||||||
|
def call(collection, params)
|
||||||
|
@collection = collection
|
||||||
|
@collection.update!(params)
|
||||||
|
|
||||||
|
distribute_update_activity if Mastodon::Feature.collections_federation_enabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def distribute_update_activity
|
||||||
|
return unless relevant_attributes_changed?
|
||||||
|
|
||||||
|
ActivityPub::AccountRawDistributionWorker.perform_async(activity_json, @collection.account.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def activity_json
|
||||||
|
ActiveModelSerializers::SerializableResource.new(@collection, serializer: ActivityPub::UpdateFeaturedCollectionSerializer, adapter: ActivityPub::Adapter).to_json
|
||||||
|
end
|
||||||
|
|
||||||
|
def relevant_attributes_changed?
|
||||||
|
(@collection.saved_changes.keys & UPDATEABLE_PARAMS).any?
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe ActivityPub::UpdateFeaturedCollectionSerializer do
|
||||||
|
subject { serialized_record_json(collection, described_class, adapter: ActivityPub::Adapter) }
|
||||||
|
|
||||||
|
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||||
|
let(:collection) { Fabricate(:collection) }
|
||||||
|
|
||||||
|
it 'serializes to the expected json' do
|
||||||
|
expect(subject).to include({
|
||||||
|
'id' => "#{tag_manager.uri_for(collection)}#updates/#{collection.updated_at.to_i}",
|
||||||
|
'type' => 'Update',
|
||||||
|
'actor' => tag_manager.uri_for(collection.account),
|
||||||
|
'to' => ['https://www.w3.org/ns/activitystreams#Public'],
|
||||||
|
'object' => a_hash_including({
|
||||||
|
'id' => tag_manager.uri_for(collection),
|
||||||
|
'type' => 'FeaturedCollection',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(subject).to_not have_key('published')
|
||||||
|
expect(subject).to_not have_key('cc')
|
||||||
|
expect(subject).to_not have_key('target')
|
||||||
|
end
|
||||||
|
end
|
||||||
43
spec/services/update_collection_service_spec.rb
Normal file
43
spec/services/update_collection_service_spec.rb
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe UpdateCollectionService do
|
||||||
|
subject { described_class.new }
|
||||||
|
|
||||||
|
let(:collection) { Fabricate(:collection) }
|
||||||
|
|
||||||
|
describe '#call' do
|
||||||
|
context 'when given valid parameters' do
|
||||||
|
it 'updates the collection' do
|
||||||
|
subject.call(collection, { name: 'Newly updated name' })
|
||||||
|
|
||||||
|
expect(collection.name).to eq 'Newly updated name'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when something actually changed' do
|
||||||
|
it 'federates an `Update` activity', feature: :collections_federation do
|
||||||
|
subject.call(collection, { name: 'updated' })
|
||||||
|
|
||||||
|
expect(ActivityPub::AccountRawDistributionWorker).to have_enqueued_sidekiq_job
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when nothing changed' do
|
||||||
|
it 'does not federate an activity', feature: :collections_federation do
|
||||||
|
subject.call(collection, { name: collection.name })
|
||||||
|
|
||||||
|
expect(ActivityPub::AccountRawDistributionWorker).to_not have_enqueued_sidekiq_job
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when given invalid parameters' do
|
||||||
|
it 'raises an exception' do
|
||||||
|
expect do
|
||||||
|
subject.call(collection, { name: '' })
|
||||||
|
end.to raise_error(ActiveRecord::RecordInvalid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
x
Reference in New Issue
Block a user