Issue FeatureAuthorizations (#38004)
This commit is contained in:
parent
3b7c33e763
commit
6b88dd4923
@ -0,0 +1,29 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ActivityPub::FeatureAuthorizationsController < ActivityPub::BaseController
|
||||||
|
include Authorization
|
||||||
|
|
||||||
|
vary_by -> { 'Signature' if authorized_fetch_mode? }
|
||||||
|
|
||||||
|
before_action :require_account_signature!, if: :authorized_fetch_mode?
|
||||||
|
before_action :set_collection_item
|
||||||
|
|
||||||
|
def show
|
||||||
|
expires_in 30.seconds, public: true if public_fetch_mode?
|
||||||
|
render json: @collection_item, serializer: ActivityPub::FeatureAuthorizationSerializer, adapter: ActivityPub::Adapter, content_type: 'application/activity+json'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def pundit_user
|
||||||
|
signed_request_account
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_collection_item
|
||||||
|
@collection_item = @account.collection_items.accepted.find(params[:id])
|
||||||
|
|
||||||
|
authorize @collection_item.collection, :show?
|
||||||
|
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
|
||||||
|
not_found
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -46,6 +46,7 @@ class Collection < ApplicationRecord
|
|||||||
scope :with_items, -> { includes(:collection_items).merge(CollectionItem.with_accounts) }
|
scope :with_items, -> { includes(:collection_items).merge(CollectionItem.with_accounts) }
|
||||||
scope :with_tag, -> { includes(:tag) }
|
scope :with_tag, -> { includes(:tag) }
|
||||||
scope :discoverable, -> { where(discoverable: true) }
|
scope :discoverable, -> { where(discoverable: true) }
|
||||||
|
scope :local, -> { where(local: true) }
|
||||||
|
|
||||||
def remote?
|
def remote?
|
||||||
!local?
|
!local?
|
||||||
|
|||||||
@ -40,6 +40,7 @@ class CollectionItem < ApplicationRecord
|
|||||||
scope :ordered, -> { order(position: :asc) }
|
scope :ordered, -> { order(position: :asc) }
|
||||||
scope :with_accounts, -> { includes(account: [:account_stat, :user]) }
|
scope :with_accounts, -> { includes(account: [:account_stat, :user]) }
|
||||||
scope :not_blocked_by, ->(account) { where.not(accounts: { id: account.blocking }) }
|
scope :not_blocked_by, ->(account) { where.not(accounts: { id: account.blocking }) }
|
||||||
|
scope :local, -> { joins(:collection).merge(Collection.local) }
|
||||||
|
|
||||||
def local_item_with_remote_account?
|
def local_item_with_remote_account?
|
||||||
local? && account&.remote?
|
local? && account&.remote?
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ActivityPub::FeatureAuthorizationSerializer < ActivityPub::Serializer
|
||||||
|
include RoutingHelper
|
||||||
|
|
||||||
|
attributes :id, :type, :interacting_object, :interaction_target
|
||||||
|
|
||||||
|
def id
|
||||||
|
ap_account_feature_authorization_url(object.account_id, object)
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
'FeatureAuthorization'
|
||||||
|
end
|
||||||
|
|
||||||
|
def interaction_target
|
||||||
|
ActivityPub::TagManager.instance.uri_for(object.account)
|
||||||
|
end
|
||||||
|
|
||||||
|
def interacting_object
|
||||||
|
ActivityPub::TagManager.instance.uri_for(object.collection)
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -1,7 +1,10 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ActivityPub::FeaturedItemSerializer < ActivityPub::Serializer
|
class ActivityPub::FeaturedItemSerializer < ActivityPub::Serializer
|
||||||
attributes :id, :type, :featured_object, :featured_object_type
|
include RoutingHelper
|
||||||
|
|
||||||
|
attributes :id, :type, :featured_object, :featured_object_type,
|
||||||
|
:feature_authorization
|
||||||
|
|
||||||
def id
|
def id
|
||||||
ActivityPub::TagManager.instance.uri_for(object)
|
ActivityPub::TagManager.instance.uri_for(object)
|
||||||
@ -18,4 +21,12 @@ class ActivityPub::FeaturedItemSerializer < ActivityPub::Serializer
|
|||||||
def featured_object_type
|
def featured_object_type
|
||||||
object.account.actor_type || 'Person'
|
object.account.actor_type || 'Person'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def feature_authorization
|
||||||
|
if object.account.local?
|
||||||
|
ap_account_feature_authorization_url(object.account_id, object)
|
||||||
|
else
|
||||||
|
object.approval_uri
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -125,6 +125,7 @@ Rails.application.routes.draw do
|
|||||||
scope path: 'ap', as: 'ap' do
|
scope path: 'ap', as: 'ap' do
|
||||||
resources :accounts, path: 'users', only: [:show], param: :id, concerns: :account_resources do
|
resources :accounts, path: 'users', only: [:show], param: :id, concerns: :account_resources do
|
||||||
resources :collection_items, only: [:show]
|
resources :collection_items, only: [:show]
|
||||||
|
resources :feature_authorizations, only: [:show], module: :activitypub
|
||||||
resources :featured_collections, only: [:index], module: :activitypub
|
resources :featured_collections, only: [:index], module: :activitypub
|
||||||
|
|
||||||
resources :statuses, only: [:show] do
|
resources :statuses, only: [:show] do
|
||||||
|
|||||||
49
spec/requests/activitypub/feature_authorizations_spec.rb
Normal file
49
spec/requests/activitypub/feature_authorizations_spec.rb
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'ActivityPub FeatureAuthorization endpoint' do
|
||||||
|
describe 'GET /ap/accounts/:account_id/feature_authorizations/:collection_item_id' do
|
||||||
|
let(:account) { Fabricate(:account) }
|
||||||
|
let(:collection) { Fabricate(:collection) }
|
||||||
|
let(:collection_item) { Fabricate(:collection_item, collection:, account:, state:) }
|
||||||
|
|
||||||
|
context 'with an accepted collection item' do
|
||||||
|
let(:state) { :accepted }
|
||||||
|
|
||||||
|
it 'returns http success and activity json' do
|
||||||
|
get ap_account_feature_authorization_path(account.id, collection_item)
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(200)
|
||||||
|
expect(response.media_type)
|
||||||
|
.to eq 'application/activity+json'
|
||||||
|
|
||||||
|
expect(response.parsed_body)
|
||||||
|
.to include(type: 'FeatureAuthorization')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples 'not found' do
|
||||||
|
it 'returns http not found' do
|
||||||
|
get ap_account_feature_authorization_path(collection.account_id, collection_item)
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a revoked collection item' do
|
||||||
|
let(:state) { :revoked }
|
||||||
|
|
||||||
|
it_behaves_like 'not found'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a collection item featuring a remote account' do
|
||||||
|
let(:account) { Fabricate(:remote_account) }
|
||||||
|
let(:state) { :accepted }
|
||||||
|
|
||||||
|
it_behaves_like 'not found'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe ActivityPub::FeatureAuthorizationSerializer do
|
||||||
|
include RoutingHelper
|
||||||
|
|
||||||
|
subject { serialized_record_json(collection_item, described_class, adapter: ActivityPub::Adapter) }
|
||||||
|
|
||||||
|
describe 'serializing an object' do
|
||||||
|
let(:collection_item) { Fabricate(:collection_item) }
|
||||||
|
let(:tag_manager) { ActivityPub::TagManager.instance }
|
||||||
|
|
||||||
|
it 'returns the expected json structure' do
|
||||||
|
expect(subject)
|
||||||
|
.to include(
|
||||||
|
'type' => 'FeatureAuthorization',
|
||||||
|
'id' => ap_account_feature_authorization_url(collection_item.account_id, collection_item),
|
||||||
|
'interactionTarget' => tag_manager.uri_for(collection_item.account),
|
||||||
|
'interactingObject' => tag_manager.uri_for(collection_item.collection)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@ -3,6 +3,8 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ActivityPub::FeaturedCollectionSerializer do
|
RSpec.describe ActivityPub::FeaturedCollectionSerializer do
|
||||||
|
include RoutingHelper
|
||||||
|
|
||||||
subject { serialized_record_json(collection, described_class, adapter: ActivityPub::Adapter) }
|
subject { serialized_record_json(collection, described_class, adapter: ActivityPub::Adapter) }
|
||||||
|
|
||||||
let(:collection) do
|
let(:collection) do
|
||||||
@ -35,12 +37,14 @@ RSpec.describe ActivityPub::FeaturedCollectionSerializer do
|
|||||||
'type' => 'FeaturedItem',
|
'type' => 'FeaturedItem',
|
||||||
'featuredObject' => ActivityPub::TagManager.instance.uri_for(collection_items.first.account),
|
'featuredObject' => ActivityPub::TagManager.instance.uri_for(collection_items.first.account),
|
||||||
'featuredObjectType' => 'Person',
|
'featuredObjectType' => 'Person',
|
||||||
|
'featureAuthorization' => ap_account_feature_authorization_url(collection_items.first.account_id, collection_items.first),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id' => ActivityPub::TagManager.instance.uri_for(collection_items.last),
|
'id' => ActivityPub::TagManager.instance.uri_for(collection_items.last),
|
||||||
'type' => 'FeaturedItem',
|
'type' => 'FeaturedItem',
|
||||||
'featuredObject' => ActivityPub::TagManager.instance.uri_for(collection_items.last.account),
|
'featuredObject' => ActivityPub::TagManager.instance.uri_for(collection_items.last.account),
|
||||||
'featuredObjectType' => 'Person',
|
'featuredObjectType' => 'Person',
|
||||||
|
'featureAuthorization' => ap_account_feature_authorization_url(collection_items.last.account_id, collection_items.last),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
'published' => match_api_datetime_format,
|
'published' => match_api_datetime_format,
|
||||||
|
|||||||
@ -3,16 +3,37 @@
|
|||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ActivityPub::FeaturedItemSerializer do
|
RSpec.describe ActivityPub::FeaturedItemSerializer do
|
||||||
|
include RoutingHelper
|
||||||
|
|
||||||
subject { serialized_record_json(collection_item, described_class, adapter: ActivityPub::Adapter) }
|
subject { serialized_record_json(collection_item, described_class, adapter: ActivityPub::Adapter) }
|
||||||
|
|
||||||
let(:collection_item) { Fabricate(:collection_item) }
|
let(:collection_item) { Fabricate(:collection_item) }
|
||||||
|
|
||||||
|
context 'when a local account is featured' do
|
||||||
|
it 'serializes to the expected structure' do
|
||||||
|
expect(subject).to include({
|
||||||
|
'type' => 'FeaturedItem',
|
||||||
|
'id' => ActivityPub::TagManager.instance.uri_for(collection_item),
|
||||||
|
'featuredObject' => ActivityPub::TagManager.instance.uri_for(collection_item.account),
|
||||||
|
'featuredObjectType' => 'Person',
|
||||||
|
'featureAuthorization' => ap_account_feature_authorization_url(collection_item.account_id, collection_item),
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a remote account is featured' do
|
||||||
|
let(:collection) { Fabricate(:collection) }
|
||||||
|
let(:account) { Fabricate(:remote_account) }
|
||||||
|
let(:collection_item) { Fabricate(:collection_item, collection:, account:, approval_uri: 'https://example.com/auth/1') }
|
||||||
|
|
||||||
it 'serializes to the expected structure' do
|
it 'serializes to the expected structure' do
|
||||||
expect(subject).to include({
|
expect(subject).to include({
|
||||||
'type' => 'FeaturedItem',
|
'type' => 'FeaturedItem',
|
||||||
'id' => ActivityPub::TagManager.instance.uri_for(collection_item),
|
'id' => ActivityPub::TagManager.instance.uri_for(collection_item),
|
||||||
'featuredObject' => ActivityPub::TagManager.instance.uri_for(collection_item.account),
|
'featuredObject' => ActivityPub::TagManager.instance.uri_for(collection_item.account),
|
||||||
'featuredObjectType' => 'Person',
|
'featuredObjectType' => 'Person',
|
||||||
|
'featureAuthorization' => 'https://example.com/auth/1',
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user