Start of handling FeatureRequest activities (#38193)
This commit is contained in:
@@ -59,6 +59,8 @@ class ActivityPub::Activity
|
|||||||
ActivityPub::Activity::Move
|
ActivityPub::Activity::Move
|
||||||
when 'QuoteRequest'
|
when 'QuoteRequest'
|
||||||
ActivityPub::Activity::QuoteRequest
|
ActivityPub::Activity::QuoteRequest
|
||||||
|
when 'FeatureRequest'
|
||||||
|
ActivityPub::Activity::FeatureRequest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
46
app/lib/activitypub/activity/feature_request.rb
Normal file
46
app/lib/activitypub/activity/feature_request.rb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ActivityPub::Activity::FeatureRequest < ActivityPub::Activity
|
||||||
|
include Payloadable
|
||||||
|
|
||||||
|
def perform
|
||||||
|
return unless Mastodon::Feature.collections_federation_enabled?
|
||||||
|
return if non_matching_uri_hosts?(@account.uri, @json['id'])
|
||||||
|
|
||||||
|
@collection = @account.collections.find_by(uri: value_or_id(@json['instrument']))
|
||||||
|
@featured_account = ActivityPub::TagManager.instance.uris_to_local_accounts([value_or_id(@json['object'])]).first
|
||||||
|
|
||||||
|
return if @collection.nil? || @featured_account.nil?
|
||||||
|
|
||||||
|
if AccountPolicy.new(@account, @featured_account).feature?
|
||||||
|
accept_request!
|
||||||
|
else
|
||||||
|
reject_request!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def accept_request!
|
||||||
|
collection_item = @collection.collection_items.create!(
|
||||||
|
account: @featured_account,
|
||||||
|
state: :accepted
|
||||||
|
)
|
||||||
|
|
||||||
|
queue_delivery!(collection_item, ActivityPub::AcceptFeatureRequestSerializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reject_request!
|
||||||
|
collection_item = @collection.collection_items.build(
|
||||||
|
account: @featured_account,
|
||||||
|
state: :rejected
|
||||||
|
)
|
||||||
|
|
||||||
|
queue_delivery!(collection_item, ActivityPub::RejectFeatureRequestSerializer)
|
||||||
|
end
|
||||||
|
|
||||||
|
def queue_delivery!(collection_item, serializer)
|
||||||
|
json = Oj.dump(serialize_payload(collection_item, serializer))
|
||||||
|
ActivityPub::DeliveryWorker.perform_async(json, @featured_account.id, @account.inbox_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -32,7 +32,7 @@ class CollectionItem < ApplicationRecord
|
|||||||
validates :approval_uri, presence: true, unless: -> { local? || account&.local? }
|
validates :approval_uri, presence: true, unless: -> { local? || account&.local? }
|
||||||
validates :account, presence: true, if: :accepted?
|
validates :account, presence: true, if: :accepted?
|
||||||
validates :object_uri, presence: true, if: -> { account.nil? }
|
validates :object_uri, presence: true, if: -> { account.nil? }
|
||||||
validates :uri, presence: true, if: :remote?
|
validates :uri, presence: true, if: :remote_item_with_remote_account?
|
||||||
|
|
||||||
before_validation :set_position, on: :create
|
before_validation :set_position, on: :create
|
||||||
before_validation :set_activity_uri, only: :create, if: :local_item_with_remote_account?
|
before_validation :set_activity_uri, only: :create, if: :local_item_with_remote_account?
|
||||||
@@ -50,6 +50,10 @@ class CollectionItem < ApplicationRecord
|
|||||||
local? && account&.remote?
|
local? && account&.remote?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remote_item_with_remote_account?
|
||||||
|
remote? && account&.remote?
|
||||||
|
end
|
||||||
|
|
||||||
def object_type
|
def object_type
|
||||||
:featured_item
|
:featured_item
|
||||||
end
|
end
|
||||||
|
|||||||
54
spec/lib/activitypub/activity/feature_request_spec.rb
Normal file
54
spec/lib/activitypub/activity/feature_request_spec.rb
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe ActivityPub::Activity::FeatureRequest do
|
||||||
|
let(:sender) { Fabricate(:remote_account) }
|
||||||
|
let(:recipient) { Fabricate(:account, discoverable:) }
|
||||||
|
let(:collection) { Fabricate(:remote_collection, account: sender) }
|
||||||
|
|
||||||
|
let(:json) do
|
||||||
|
{
|
||||||
|
'@context' => [
|
||||||
|
'https://www.w3.org/ns/activitystreams',
|
||||||
|
],
|
||||||
|
'id' => 'https://example.com/feature_requests/1',
|
||||||
|
'type' => 'FeatureRequest',
|
||||||
|
'actor' => sender.uri,
|
||||||
|
'object' => ActivityPub::TagManager.instance.uri_for(recipient),
|
||||||
|
'instrument' => collection.uri,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#perform', feature: :collections_federation do
|
||||||
|
subject { described_class.new(json, sender) }
|
||||||
|
|
||||||
|
context 'when recipient is discoverable' do
|
||||||
|
let(:discoverable) { true }
|
||||||
|
|
||||||
|
it 'schedules a job to send an `Accept` activity' do
|
||||||
|
expect { subject.perform }
|
||||||
|
.to enqueue_sidekiq_job(ActivityPub::DeliveryWorker)
|
||||||
|
.with(satisfying do |body|
|
||||||
|
response_json = JSON.parse(body)
|
||||||
|
response_json['type'] == 'Accept' &&
|
||||||
|
response_json['to'] == sender.uri
|
||||||
|
end, recipient.id, sender.inbox_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when recipient is not discoverable' do
|
||||||
|
let(:discoverable) { false }
|
||||||
|
|
||||||
|
it 'schedules a job to send a `Reject` activity' do
|
||||||
|
expect { subject.perform }
|
||||||
|
.to enqueue_sidekiq_job(ActivityPub::DeliveryWorker)
|
||||||
|
.with(satisfying do |body|
|
||||||
|
response_json = JSON.parse(body)
|
||||||
|
response_json['type'] == 'Reject' &&
|
||||||
|
response_json['to'] == sender.uri
|
||||||
|
end, recipient.id, sender.inbox_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -17,8 +17,9 @@ RSpec.describe CollectionItem do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when item is not local' do
|
context 'when item is not local' do
|
||||||
subject { Fabricate.build(:collection_item, collection: remote_collection) }
|
subject { Fabricate.build(:collection_item, collection: remote_collection, account:) }
|
||||||
|
|
||||||
|
let(:account) { Fabricate.build(:remote_account) }
|
||||||
let(:remote_collection) { Fabricate.build(:collection, local: false) }
|
let(:remote_collection) { Fabricate.build(:collection, local: false) }
|
||||||
|
|
||||||
it { is_expected.to validate_presence_of(:uri) }
|
it { is_expected.to validate_presence_of(:uri) }
|
||||||
@@ -28,6 +29,12 @@ RSpec.describe CollectionItem do
|
|||||||
|
|
||||||
it { is_expected.to validate_presence_of(:approval_uri) }
|
it { is_expected.to validate_presence_of(:approval_uri) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when account is local' do
|
||||||
|
let(:account) { Fabricate.build(:account) }
|
||||||
|
|
||||||
|
it { is_expected.to_not validate_presence_of(:uri) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when account is not present' do
|
context 'when account is not present' do
|
||||||
|
|||||||
Reference in New Issue
Block a user