Remove collections feature flag (#39211)

This commit is contained in:
David Roetzel 2026-05-29 11:37:42 +02:00 committed by GitHub
parent e2754b0bc2
commit 572612fde9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 166 additions and 226 deletions

View File

@ -9,7 +9,6 @@ class ActivityPub::FeaturedCollectionsController < ApplicationController
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' } vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :check_feature_enabled
before_action :require_account_signature!, if: -> { authorized_fetch_mode? } before_action :require_account_signature!, if: -> { authorized_fetch_mode? }
before_action :set_collections before_action :set_collections
@ -72,8 +71,4 @@ class ActivityPub::FeaturedCollectionsController < ApplicationController
) )
end end
end end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end end

View File

@ -25,6 +25,8 @@ module Admin
@action_logs = @report.history.includes(:target) @action_logs = @report.history.includes(:target)
@form = Admin::StatusBatchAction.new @form = Admin::StatusBatchAction.new
@statuses = @report.statuses.with_includes @statuses = @report.statuses.with_includes
@collections = @report.collections
@collection_form = Admin::CollectionBatchAction.new
render 'admin/reports/show' render 'admin/reports/show'
end end

View File

@ -3,8 +3,6 @@
class Api::V1::CollectionItemsController < Api::BaseController class Api::V1::CollectionItemsController < Api::BaseController
include Authorization include Authorization
before_action :check_feature_enabled
before_action -> { doorkeeper_authorize! :write, :'write:collections' } before_action -> { doorkeeper_authorize! :write, :'write:collections' }
before_action :require_user! before_action :require_user!
@ -55,8 +53,4 @@ class Api::V1::CollectionItemsController < Api::BaseController
def set_collection_item def set_collection_item
@collection_item = @collection.collection_items.find(params[:id]) @collection_item = @collection.collection_items.find(params[:id])
end end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end end

View File

@ -9,8 +9,6 @@ class Api::V1::CollectionsController < Api::BaseController
render json: { error: ValidationErrorFormatter.new(e).as_json }, status: 422 render json: { error: ValidationErrorFormatter.new(e).as_json }, status: 422
end end
before_action :check_feature_enabled
before_action -> { authorize_if_got_token! :read, :'read:collections' }, only: [:index, :show] before_action -> { authorize_if_got_token! :read, :'read:collections' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :write, :'write:collections' }, only: [:create, :update, :destroy] before_action -> { doorkeeper_authorize! :write, :'write:collections' }, only: [:create, :update, :destroy]
@ -91,10 +89,6 @@ class Api::V1::CollectionsController < Api::BaseController
params.permit(:name, :description, :language, :sensitive, :discoverable, :tag_name) params.permit(:name, :description, :language, :sensitive, :discoverable, :tag_name)
end end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
def next_path def next_path
return unless records_continue? return unless records_continue?

View File

@ -5,8 +5,6 @@ class Api::V1::InCollectionsController < Api::BaseController
DEFAULT_COLLECTIONS_LIMIT = 40 DEFAULT_COLLECTIONS_LIMIT = 40
before_action :check_feature_enabled
before_action -> { authorize_if_got_token! :read, :'read:collections' }, only: [:index] before_action -> { authorize_if_got_token! :read, :'read:collections' }, only: [:index]
before_action :require_user! before_action :require_user!
@ -37,10 +35,6 @@ class Api::V1::InCollectionsController < Api::BaseController
.limit(limit_param(DEFAULT_COLLECTIONS_LIMIT)) .limit(limit_param(DEFAULT_COLLECTIONS_LIMIT))
end end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
def next_path def next_path
return unless records_continue? return unless records_continue?

View File

@ -23,10 +23,6 @@ class Api::V1::ReportsController < Api::BaseController
end end
def report_params def report_params
if Mastodon::Feature.collections_enabled? params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], collection_ids: [], rule_ids: [])
params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], collection_ids: [], rule_ids: [])
else
params.permit(:account_id, :comment, :category, :forward, forward_to_domains: [], status_ids: [], rule_ids: [])
end
end end
end end

View File

@ -170,6 +170,6 @@ class Api::V1::StatusesController < Api::BaseController
end end
def serialized_accounts(accounts) def serialized_accounts(accounts)
ActiveModel::Serializer::CollectionSerializer.new(accounts, serializer: REST::AccountSerializer) ActiveModel::Serializer::CollectionSerializer.new(accounts, serializer: REST::AccountSerializer, scope_name: :current_user, scope: current_user)
end end
end end

View File

@ -7,7 +7,6 @@ class CollectionItemsController < ApplicationController
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' } vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :check_feature_enabled
before_action :require_account_signature!, if: -> { authorized_fetch_mode? } before_action :require_account_signature!, if: -> { authorized_fetch_mode? }
before_action :set_collection_item before_action :set_collection_item
@ -35,8 +34,4 @@ class CollectionItemsController < ApplicationController
rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError rescue ActiveRecord::RecordNotFound, Mastodon::NotPermittedError
not_found not_found
end end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end end

View File

@ -8,7 +8,6 @@ class CollectionsController < ApplicationController
vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' } vary_by -> { public_fetch_mode? ? 'Accept, Accept-Language, Cookie' : 'Accept, Accept-Language, Cookie, Signature' }
before_action :check_feature_enabled
before_action :require_account_signature!, only: :show, if: -> { request.format == :json && authorized_fetch_mode? } before_action :require_account_signature!, only: :show, if: -> { request.format == :json && authorized_fetch_mode? }
before_action :set_collection before_action :set_collection
@ -51,8 +50,4 @@ class CollectionsController < ApplicationController
recently_updated = @collection.updated_at > 15.minutes.ago recently_updated = @collection.updated_at > 15.minutes.ago
recently_updated ? 30.seconds : 5.minutes recently_updated ? 30.seconds : 5.minutes
end end
def check_feature_enabled
raise ActionController::RoutingError unless Mastodon::Feature.collections_enabled?
end
end end

View File

@ -5,7 +5,7 @@ class ActivityPub::Activity::Accept < ActivityPub::Activity
return accept_follow_for_relay if relay_follow? return accept_follow_for_relay if relay_follow?
return accept_follow!(follow_request_from_object) unless follow_request_from_object.nil? return accept_follow!(follow_request_from_object) unless follow_request_from_object.nil?
return accept_quote!(quote_request_from_object) unless quote_request_from_object.nil? return accept_quote!(quote_request_from_object) unless quote_request_from_object.nil?
return accept_feature_request! if Mastodon::Feature.collections_enabled? && feature_request_from_object.present? return accept_feature_request! if feature_request_from_object.present?
case @object['type'] case @object['type']
when 'Follow' when 'Follow'

View File

@ -13,12 +13,10 @@ class ActivityPub::Activity::Add < ActivityPub::Activity
add_featured add_featured
end end
when @account.collections_url when @account.collections_url
return unless Mastodon::Feature.collections_enabled?
add_collection add_collection
else else
@collection = @account.collections.find_by(uri: value_or_id(@json['target'])) @collection = @account.collections.find_by(uri: value_or_id(@json['target']))
add_collection_item if @collection && Mastodon::Feature.collections_enabled? add_collection_item if @collection
end end
end end

View File

@ -3,7 +3,7 @@
class ActivityPub::Activity::Delete < ActivityPub::Activity class ActivityPub::Activity::Delete < ActivityPub::Activity
def perform def perform
return delete_person if @account.uri == object_uri return delete_person if @account.uri == object_uri
return delete_feature_authorization! unless !Mastodon::Feature.collections_enabled? || feature_authorization_from_object.nil? return delete_feature_authorization! unless feature_authorization_from_object.nil?
delete_object delete_object
end end

View File

@ -4,7 +4,6 @@ class ActivityPub::Activity::FeatureRequest < ActivityPub::Activity
include Payloadable include Payloadable
def perform def perform
return unless Mastodon::Feature.collections_enabled?
return if non_matching_uri_hosts?(@account.uri, @json['id']) return if non_matching_uri_hosts?(@account.uri, @json['id'])
@collection = find_or_fetch_collection @collection = find_or_fetch_collection

View File

@ -13,7 +13,7 @@ class ActivityPub::Activity::Update < ActivityPub::Activity
update_account update_account
elsif supported_object_type? || converted_object_type? elsif supported_object_type? || converted_object_type?
update_status update_status
elsif equals_or_includes_any?(@object['type'], ['FeaturedCollection']) && Mastodon::Feature.collections_enabled? elsif equals_or_includes_any?(@object['type'], ['FeaturedCollection'])
update_collection update_collection
end end
end end

View File

@ -121,7 +121,6 @@ class StatusCacheHydrator
end end
def hydrate_account(payload, account) def hydrate_account(payload, account)
return unless Mastodon::Feature.collections_enabled?
return unless payload[:id] return unless payload[:id]
stale_account = Account.find_by(id: payload[:id]) stale_account = Account.find_by(id: payload[:id])

View File

@ -10,7 +10,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
:moved_to, :property_value, :discoverable, :suspended, :moved_to, :property_value, :discoverable, :suspended,
:memorial, :indexable, :attribution_domains, :profile_settings :memorial, :indexable, :attribution_domains, :profile_settings
context_extensions :interaction_policies if Mastodon::Feature.collections_enabled? context_extensions :interaction_policies
attributes :id, :webfinger, :type, :following, :followers, attributes :id, :webfinger, :type, :following, :followers,
:inbox, :outbox, :featured, :featured_tags, :inbox, :outbox, :featured, :featured_tags,
@ -21,8 +21,8 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
attribute :show_media_replies, key: :show_replies_in_media attribute :show_media_replies, key: :show_replies_in_media
attribute :interaction_policy, if: -> { Mastodon::Feature.collections_enabled? } attribute :interaction_policy
attribute :featured_collections, if: -> { Mastodon::Feature.collections_enabled? } attribute :featured_collections
has_one :public_key, serializer: ActivityPub::PublicKeySerializer has_one :public_key, serializer: ActivityPub::PublicKeySerializer

View File

@ -21,7 +21,7 @@ class REST::AccountSerializer < ActiveModel::Serializer
attribute :memorial, if: :memorial? attribute :memorial, if: :memorial?
attribute :feature_approval, if: -> { Mastodon::Feature.collections_enabled? } attribute :feature_approval
attribute :email_subscriptions, if: -> { Rails.application.config.x.email_subscriptions && Setting.email_subscriptions } attribute :email_subscriptions, if: -> { Rails.application.config.x.email_subscriptions && Setting.email_subscriptions }
class AccountDecorator < SimpleDelegator class AccountDecorator < SimpleDelegator

View File

@ -3,7 +3,7 @@
class REST::RoleSerializer < ActiveModel::Serializer class REST::RoleSerializer < ActiveModel::Serializer
attributes :id, :name, :permissions, :color, :highlighted attributes :id, :name, :permissions, :color, :highlighted
attribute :collection_limit, if: -> { Mastodon::Feature.collections_enabled? } attribute :collection_limit
def id def id
object.id.to_s object.id.to_s

View File

@ -72,7 +72,7 @@ class ActivityPub::ProcessAccountService < BaseService
unless @options[:only_key] || @account.suspended? unless @options[:only_key] || @account.suspended?
check_featured_collection! if @json['featured'].present? check_featured_collection! if @json['featured'].present?
check_featured_tags_collection! if @json['featuredTags'].present? check_featured_tags_collection! if @json['featuredTags'].present?
check_featured_collections_collection! if @json['featuredCollections'].present? && Mastodon::Feature.collections_enabled? check_featured_collections_collection! if @json['featuredCollections'].present?
check_links! if @account.fields.any?(&:requires_verification?) check_links! if @account.fields.any?(&:requires_verification?)
end end
@ -121,7 +121,7 @@ class ActivityPub::ProcessAccountService < BaseService
@account.uri = @uri @account.uri = @uri
@account.actor_type = actor_type @account.actor_type = actor_type
@account.created_at = @json['published'] if @json['published'].present? @account.created_at = @json['published'] if @json['published'].present?
@account.feature_approval_policy = feature_approval_policy if Mastodon::Feature.collections_enabled? @account.feature_approval_policy = feature_approval_policy
end end
def valid_collection_uri(uri) def valid_collection_uri(uri)

View File

@ -28,7 +28,7 @@ class ResolveURLService < BaseService
status = FetchRemoteStatusService.new.call(resource_url, prefetched_body: body) status = FetchRemoteStatusService.new.call(resource_url, prefetched_body: body)
authorize_with @on_behalf_of, status, :show? unless status.nil? authorize_with @on_behalf_of, status, :show? unless status.nil?
status status
elsif type == 'FeaturedCollection' && Mastodon::Feature.collections_enabled? elsif type == 'FeaturedCollection'
collection = ActivityPub::FetchRemoteFeaturedCollectionService.new.call(resource_url, prefetched_body: body) collection = ActivityPub::FetchRemoteFeaturedCollectionService.new.call(resource_url, prefetched_body: body)
authorize_with @on_behalf_of, collection, :show? unless collection.nil? authorize_with @on_behalf_of, collection, :show? unless collection.nil?
collection collection

View File

@ -67,10 +67,9 @@
= material_symbol('photo_camera') = material_symbol('photo_camera')
= report.media_attachments_count = report.media_attachments_count
- if Mastodon::Feature.collections_enabled? %span.report-card__summary__item__content__icon{ title: t('admin.accounts.collections') }
%span.report-card__summary__item__content__icon{ title: t('admin.accounts.collections') } = material_symbol('category')
= material_symbol('category') = report.collections.size
= report.collections.size
- if report.forwarded? - if report.forwarded?
· ·

View File

@ -62,27 +62,26 @@
- else - else
= render partial: 'admin/shared/status_batch_row', collection: @statuses, as: :status, locals: { f: f } = render partial: 'admin/shared/status_batch_row', collection: @statuses, as: :status, locals: { f: f }
- if Mastodon::Feature.collections_enabled? %details{ open: @collections.any? }
%details{ open: @collections.any? } %summary
%summary = t 'admin.reports.collections', count: @collections.size
= t 'admin.reports.collections', count: @collections.size
= form_with model: @collection_form, url: batch_admin_account_collections_path(@report.target_account_id, report_id: @report.id) do |f| = form_with model: @collection_form, url: batch_admin_account_collections_path(@report.target_account_id, report_id: @report.id) do |f|
.batch-table .batch-table
.batch-table__toolbar .batch-table__toolbar
%label.batch-table__toolbar__select.batch-checkbox-all %label.batch-table__toolbar__select.batch-checkbox-all
= check_box_tag :batch_checkbox_all, nil, false = check_box_tag :batch_checkbox_all, nil, false
.batch-table__toolbar__actions .batch-table__toolbar__actions
= link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]), = link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]),
admin_account_collections_path(@report.target_account_id, report_id: @report.id), admin_account_collections_path(@report.target_account_id, report_id: @report.id),
class: 'table-action-link' class: 'table-action-link'
- if !@collections.empty? && @report.unresolved? - if !@collections.empty? && @report.unresolved?
= f.button safe_join([material_symbol('close'), t('admin.collections.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit = f.button safe_join([material_symbol('close'), t('admin.collections.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit
.batch-table__body .batch-table__body
- if @collections.empty? - if @collections.empty?
= nothing_here 'nothing-here--under-tabs' = nothing_here 'nothing-here--under-tabs'
- else - else
= render partial: 'admin/shared/collection_batch_row', collection: @collections, as: :collection, locals: { f: f } = render partial: 'admin/shared/collection_batch_row', collection: @collections, as: :collection, locals: { f: f }
- if @report.unresolved? - if @report.unresolved?
%hr.spacer/ %hr.spacer/

View File

@ -32,13 +32,11 @@
%hr.spacer/ %hr.spacer/
- if Mastodon::Feature.collections_enabled? .fields-group
= form.input :collection_limit,
wrapper: :with_label
.fields-group %hr.spacer/
= form.input :collection_limit,
wrapper: :with_label
%hr.spacer/
- unless current_user.role == form.object - unless current_user.role == form.object

View File

@ -172,7 +172,7 @@ RSpec.describe ActivityPub::Activity::Accept do
end end
end end
context 'with a FeatureRequest', feature: :collections do context 'with a FeatureRequest' do
let(:collection) { Fabricate(:collection, account: recipient) } let(:collection) { Fabricate(:collection, account: recipient) }
let(:collection_item) { Fabricate(:collection_item, collection:, account: sender, state: :pending) } let(:collection_item) { Fabricate(:collection_item, collection:, account: sender, state: :pending) }
let(:object) { collection_item.activity_uri } let(:object) { collection_item.activity_uri }

View File

@ -80,7 +80,7 @@ RSpec.describe ActivityPub::Activity::Add do
end end
end end
context 'when the target is the `featuredCollections` collection', feature: :collections do context 'when the target is the `featuredCollections` collection' do
subject { described_class.new(activity_json, account) } subject { described_class.new(activity_json, account) }
let(:account) { Fabricate(:remote_account, collections_url: 'https://example.com/actor/1/featured_collections') } let(:account) { Fabricate(:remote_account, collections_url: 'https://example.com/actor/1/featured_collections') }
@ -122,7 +122,7 @@ RSpec.describe ActivityPub::Activity::Add do
end end
end end
context 'when the target is a collection', feature: :collections do context 'when the target is a collection' do
subject { described_class.new(activity_json, collection.account) } subject { described_class.new(activity_json, collection.account) }
let(:collection) { Fabricate(:remote_collection) } let(:collection) { Fabricate(:remote_collection) }

View File

@ -120,7 +120,7 @@ RSpec.describe ActivityPub::Activity::Delete do
end end
end end
context 'with a FeatureAuthorization', feature: :collections do context 'with a FeatureAuthorization' do
let(:recipient) { Fabricate(:account) } let(:recipient) { Fabricate(:account) }
let(:approval_uri) { 'https://example.com/authorizations/1' } let(:approval_uri) { 'https://example.com/authorizations/1' }
let(:collection) { Fabricate(:collection, account: recipient) } let(:collection) { Fabricate(:collection, account: recipient) }

View File

@ -20,7 +20,7 @@ RSpec.describe ActivityPub::Activity::FeatureRequest do
} }
end end
describe '#perform', feature: :collections do describe '#perform' do
subject { described_class.new(json, sender) } subject { described_class.new(json, sender) }
context 'when recipient is discoverable' do context 'when recipient is discoverable' do

View File

@ -257,7 +257,7 @@ RSpec.describe ActivityPub::Activity::Update do
end end
end end
context 'with a `FeaturedCollection` object', feature: :collections do context 'with a `FeaturedCollection` object' do
let(:collection) { Fabricate(:remote_collection, account: sender, name: 'old name', discoverable: false) } let(:collection) { Fabricate(:remote_collection, account: sender, name: 'old name', discoverable: false) }
let(:account) { Fabricate(:account) } let(:account) { Fabricate(:account) }
let!(:collection_item) { Fabricate(:collection_item, account:, collection:, uri: 'https://example.com/featured_stamps/1') } let!(:collection_item) { Fabricate(:collection_item, account:, collection:, uri: 'https://example.com/featured_stamps/1') }

View File

@ -6,7 +6,7 @@ RSpec.describe StatusCacheHydrator do
let(:status) { Fabricate(:status) } let(:status) { Fabricate(:status) }
let(:account) { Fabricate(:account) } let(:account) { Fabricate(:account) }
describe '#hydrate', feature: :collections do describe '#hydrate' do
let(:compare_to_hash) { InlineRenderer.render(status, account, :status) } let(:compare_to_hash) { InlineRenderer.render(status, account, :status) }
shared_examples 'shared behavior' do shared_examples 'shared behavior' do

View File

@ -33,7 +33,7 @@ RSpec.describe Admin::ModerationAction do
expect(report.reload).to be_action_taken expect(report.reload).to be_action_taken
end end
context 'with attached collections', feature: :collections do context 'with attached collections' do
let(:status_ids) { [] } let(:status_ids) { [] }
let(:collections) { Fabricate.times(2, :collection, account: target_account) } let(:collections) { Fabricate.times(2, :collection, account: target_account) }
@ -47,7 +47,7 @@ RSpec.describe Admin::ModerationAction do
end end
end end
context 'with a remote collection', feature: :collections do context 'with a remote collection' do
let(:status_ids) { [] } let(:status_ids) { [] }
let(:collection) { Fabricate(:remote_collection) } let(:collection) { Fabricate(:remote_collection) }
let(:target_account) { collection.account } let(:target_account) { collection.account }
@ -83,7 +83,7 @@ RSpec.describe Admin::ModerationAction do
expect(report.reload).to be_action_taken expect(report.reload).to be_action_taken
end end
context 'with attached collections', feature: :collections do context 'with attached collections' do
let(:status_ids) { [] } let(:status_ids) { [] }
let(:collections) { Fabricate.times(2, :collection, account: target_account) } let(:collections) { Fabricate.times(2, :collection, account: target_account) }

View File

@ -3,7 +3,7 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'Collections' do RSpec.describe 'Collections' do
describe 'GET /ap/users/@:account_id/featured_collections', feature: :collections do describe 'GET /ap/users/@:account_id/featured_collections' do
subject { get ap_account_featured_collections_path(account.id, format: :json) } subject { get ap_account_featured_collections_path(account.id, format: :json) }
let(:collection) { Fabricate(:collection) } let(:collection) { Fabricate(:collection) }

View File

@ -47,7 +47,7 @@ RSpec.describe 'Admin Reports' do
it_behaves_like 'successful return' it_behaves_like 'successful return'
end end
context 'with a reported collection', feature: :collections do context 'with a reported collection' do
before do before do
report.collections << Fabricate(:collection, account: report.target_account) report.collections << Fabricate(:collection, account: report.target_account)
end end
@ -55,7 +55,7 @@ RSpec.describe 'Admin Reports' do
it_behaves_like 'successful return' it_behaves_like 'successful return'
end end
context 'with both status and collection', feature: :collections do context 'with both status and collection' do
before do before do
status = Fabricate(:status, account: report.target_account) status = Fabricate(:status, account: report.target_account)
report.update(status_ids: [status.id]) report.update(status_ids: [status.id])

View File

@ -2,7 +2,7 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'Api::V1Alpha::CollectionItems', feature: :collections do RSpec.describe 'Api::V1Alpha::CollectionItems' do
include_context 'with API authentication', oauth_scopes: 'read:collections write:collections' include_context 'with API authentication', oauth_scopes: 'read:collections write:collections'
describe 'POST /api/v1_alpha/collections/:collection_id/items' do describe 'POST /api/v1_alpha/collections/:collection_id/items' do

View File

@ -2,7 +2,7 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'Api::V1::Collections', feature: :collections do RSpec.describe 'Api::V1::Collections' do
include_context 'with API authentication', oauth_scopes: 'read:collections write:collections' include_context 'with API authentication', oauth_scopes: 'read:collections write:collections'
describe 'GET /api/v1/accounts/:account_id/collections' do describe 'GET /api/v1/accounts/:account_id/collections' do

View File

@ -2,7 +2,7 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'Api::V1::InCollections', feature: :collections do RSpec.describe 'Api::V1::InCollections' do
include_context 'with API authentication', oauth_scopes: 'read:collections write:collections' include_context 'with API authentication', oauth_scopes: 'read:collections write:collections'
describe 'GET /api/v1/in_collections' do describe 'GET /api/v1/in_collections' do

View File

@ -113,7 +113,7 @@ RSpec.describe 'Reports' do
end end
end end
context 'with attached collection', feature: :collections do context 'with attached collection' do
let(:collection) { Fabricate(:collection, account: target_account) } let(:collection) { Fabricate(:collection, account: target_account) }
let(:collection_ids) { [collection.id] } let(:collection_ids) { [collection.id] }

View File

@ -3,7 +3,7 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'CollectionItems' do RSpec.describe 'CollectionItems' do
describe 'GET /ap/users/@:account_id/collection_items/:id', feature: :collections do describe 'GET /ap/users/@:account_id/collection_items/:id' do
subject { get ap_account_collection_item_path(account.id, collection_item, format: :json) } subject { get ap_account_collection_item_path(account.id, collection_item, format: :json) }
let(:collection_item) { Fabricate(:collection_item) } let(:collection_item) { Fabricate(:collection_item) }

View File

@ -3,7 +3,7 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe 'Collections' do RSpec.describe 'Collections' do
describe 'GET /collections/:id', feature: :collections do describe 'GET /collections/:id' do
subject { get collection_path(collection) } subject { get collection_path(collection) }
let(:collection) { Fabricate(:collection) } let(:collection) { Fabricate(:collection) }
@ -15,7 +15,7 @@ RSpec.describe 'Collections' do
end end
end end
describe 'GET /ap/:account_id/collections/:id', feature: :collections do describe 'GET /ap/:account_id/collections/:id' do
subject { get ap_account_collection_path(account.id, collection, format: :json) } subject { get ap_account_collection_path(account.id, collection, format: :json) }
let(:collection) { Fabricate(:collection) } let(:collection) { Fabricate(:collection) }

View File

@ -40,46 +40,37 @@ RSpec.describe ActivityPub::ActorSerializer do
describe '#interactionPolicy' do describe '#interactionPolicy' do
let(:record) { Fabricate(:account) } let(:record) { Fabricate(:account) }
# TODO: Remove when feature flag is removed context 'when actor is discoverable' do
context 'when collections feature is disabled?' do it 'includes an automatic policy allowing everyone' do
it 'is not present' do expect(subject).to include('interactionPolicy' => {
expect(subject).to_not have_key('interactionPolicy') 'canFeature' => {
'automaticApproval' => ['https://www.w3.org/ns/activitystreams#Public'],
},
})
end
context 'when actor is locked' do
let(:record) { Fabricate(:account, locked: true) }
it 'includes an automatic policy allowing followers' do
expect(subject).to include('interactionPolicy' => {
'canFeature' => {
'automaticApproval' => [ActivityPub::TagManager.instance.followers_uri_for(record)],
},
})
end
end end
end end
context 'when collections feature is enabled', feature: :collections do context 'when actor is not discoverable' do
context 'when actor is discoverable' do let(:record) { Fabricate(:account, discoverable: false) }
it 'includes an automatic policy allowing everyone' do
expect(subject).to include('interactionPolicy' => {
'canFeature' => {
'automaticApproval' => ['https://www.w3.org/ns/activitystreams#Public'],
},
})
end
context 'when actor is locked' do it 'includes an automatic policy limited to the actor itself' do
let(:record) { Fabricate(:account, locked: true) } expect(subject).to include('interactionPolicy' => {
'canFeature' => {
it 'includes an automatic policy allowing followers' do 'automaticApproval' => [ActivityPub::TagManager.instance.uri_for(record)],
expect(subject).to include('interactionPolicy' => { },
'canFeature' => { })
'automaticApproval' => [ActivityPub::TagManager.instance.followers_uri_for(record)],
},
})
end
end
end
context 'when actor is not discoverable' do
let(:record) { Fabricate(:account, discoverable: false) }
it 'includes an automatic policy limited to the actor itself' do
expect(subject).to include('interactionPolicy' => {
'canFeature' => {
'automaticApproval' => [ActivityPub::TagManager.instance.uri_for(record)],
},
})
end
end end
end end
end end

View File

@ -38,7 +38,7 @@ RSpec.describe ActivityPub::FlagSerializer do
end end
end end
context 'with collection', feature: :collections do context 'with collection' do
let(:target_account) { Fabricate(:account) } let(:target_account) { Fabricate(:account) }
let(:collection) { Fabricate(:collection, account: target_account) } let(:collection) { Fabricate(:collection, account: target_account) }
let(:report) { Fabricate(:report, target_account:, collections: [collection]) } let(:report) { Fabricate(:report, target_account:, collections: [collection]) }

View File

@ -76,75 +76,66 @@ RSpec.describe REST::AccountSerializer do
end end
describe '#feature_approval' do describe '#feature_approval' do
# TODO: Remove when feature flag is removed context 'when account is local' do
context 'when collections feature is disabled' do context 'when account is discoverable' do
it 'does not include the approval policy' do it 'includes a policy that allows featuring' do
expect(subject).to_not have_key('feature_approval')
end
end
context 'when collections feature is enabled', feature: :collections do
context 'when account is local' do
context 'when account is discoverable' do
it 'includes a policy that allows featuring' do
expect(subject['feature_approval']).to include({
'automatic' => ['public'],
'manual' => [],
'current_user' => 'automatic',
})
end
context 'when account is locked' do
let(:account) { Fabricate(:account, locked: true) }
context 'when the current account does not follow the user' do
it 'includes a policy that allows featuring for followers and has "denied" for the current user' do
expect(subject['feature_approval']).to include({
'automatic' => ['followers'],
'manual' => [],
'current_user' => 'denied',
})
end
end
context 'when the current account follows the user' do
before { current_user.account.follow!(account) }
it 'includes a policy that allows featuring for followers and has "automatic" for the current user' do
expect(subject['feature_approval']).to include({
'automatic' => ['followers'],
'manual' => [],
'current_user' => 'automatic',
})
end
end
end
end
context 'when account is not discoverable' do
let(:account) { Fabricate(:account, discoverable: false) }
it 'includes a policy that disallows featuring' do
expect(subject['feature_approval']).to include({
'automatic' => [],
'manual' => [],
'current_user' => 'denied',
})
end
end
end
context 'when account is remote' do
let(:account) { Fabricate(:account, domain: 'example.com', feature_approval_policy: 0b11000000000000000010) }
it 'includes the matching policy' do
expect(subject['feature_approval']).to include({ expect(subject['feature_approval']).to include({
'automatic' => ['followers', 'following'], 'automatic' => ['public'],
'manual' => ['public'], 'manual' => [],
'current_user' => 'manual', 'current_user' => 'automatic',
})
end
context 'when account is locked' do
let(:account) { Fabricate(:account, locked: true) }
context 'when the current account does not follow the user' do
it 'includes a policy that allows featuring for followers and has "denied" for the current user' do
expect(subject['feature_approval']).to include({
'automatic' => ['followers'],
'manual' => [],
'current_user' => 'denied',
})
end
end
context 'when the current account follows the user' do
before { current_user.account.follow!(account) }
it 'includes a policy that allows featuring for followers and has "automatic" for the current user' do
expect(subject['feature_approval']).to include({
'automatic' => ['followers'],
'manual' => [],
'current_user' => 'automatic',
})
end
end
end
end
context 'when account is not discoverable' do
let(:account) { Fabricate(:account, discoverable: false) }
it 'includes a policy that disallows featuring' do
expect(subject['feature_approval']).to include({
'automatic' => [],
'manual' => [],
'current_user' => 'denied',
}) })
end end
end end
end end
context 'when account is remote' do
let(:account) { Fabricate(:account, domain: 'example.com', feature_approval_policy: 0b11000000000000000010) }
it 'includes the matching policy' do
expect(subject['feature_approval']).to include({
'automatic' => ['followers', 'following'],
'manual' => ['public'],
'current_user' => 'manual',
})
end
end
end end
end end

View File

@ -3,8 +3,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe REST::AccountWarningSerializer do RSpec.describe REST::AccountWarningSerializer do
subject { serialized_record_json(record, described_class) } subject { serialized_record_json(record, described_class, options: { scope: current_user, scope_name: :current_user }) }
let(:current_user) { Fabricate(:moderator_user) }
let(:record) { Fabricate :account_warning, id: 123, status_ids: [456, 789] } let(:record) { Fabricate :account_warning, id: 123, status_ids: [456, 789] }
describe 'serialization' do describe 'serialization' do

View File

@ -3,7 +3,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe REST::Admin::AccountSerializer do RSpec.describe REST::Admin::AccountSerializer do
subject { serialized_record_json(record, described_class) } subject { serialized_record_json(record, described_class, options: { scope: current_user, scope_name: :current_user }) }
let(:current_user) { Fabricate(:admin_user) }
context 'when created_at is populated' do context 'when created_at is populated' do
let(:record) { Fabricate :account, user: Fabricate(:user) } let(:record) { Fabricate :account, user: Fabricate(:user) }

View File

@ -3,7 +3,7 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe REST::Admin::ReportSerializer do RSpec.describe REST::Admin::ReportSerializer do
subject { serialized_record_json(report, described_class) } subject { serialized_record_json(report, described_class, options: { scope_name: :current_user, scope: nil }) }
context 'with timestamps' do context 'with timestamps' do
let(:report) { Fabricate(:report, action_taken_at: 3.days.ago) } let(:report) { Fabricate(:report, action_taken_at: 3.days.ago) }

View File

@ -6,10 +6,16 @@ RSpec.describe REST::ReportSerializer do
subject do subject do
serialized_record_json( serialized_record_json(
report, report,
described_class described_class,
options: {
scope: current_user,
scope_name: :current_user,
}
) )
end end
let(:current_user) { Fabricate(:moderator_user) }
context 'with timestamps' do context 'with timestamps' do
let(:report) { Fabricate(:report, action_taken_at: 3.days.ago) } let(:report) { Fabricate(:report, action_taken_at: 3.days.ago) }

View File

@ -27,7 +27,7 @@ RSpec.describe REST::RoleSerializer do
}) })
end end
context 'when collections are enabled', feature: :collections do context 'when collections are enabled' do
it 'includes the relevant attributes' do it 'includes the relevant attributes' do
expect(subject) expect(subject)
.to include({ .to include({

View File

@ -3,7 +3,8 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe REST::SuggestionSerializer do RSpec.describe REST::SuggestionSerializer do
let(:serialization) { serialized_record_json(record, described_class) } let(:serialization) { serialized_record_json(record, described_class, options: { scope: current_user, scope_name: :current_user }) }
let(:current_user) { Fabricate(:user) }
let(:record) do let(:record) do
AccountSuggestions::Suggestion.new( AccountSuggestions::Suggestion.new(
account: account, account: account,

View File

@ -63,7 +63,7 @@ RSpec.describe ActivityPub::ProcessAccountService do
end end
end end
context 'with collection URIs', feature: :collections do context 'with collection URIs' do
let(:payload) do let(:payload) do
{ {
'id' => 'https://foo.test', 'id' => 'https://foo.test',
@ -562,16 +562,7 @@ RSpec.describe ActivityPub::ProcessAccountService do
.to_return(status: 200, body: '', headers: {}) .to_return(status: 200, body: '', headers: {})
end end
# TODO: Remove when feature flag is removed context 'when collections feature is enabled' do
context 'when collections feature is disabled' do
it 'does not set the interaction policy' do
account = subject.call('user1', 'foo.test', payload)
expect(account.feature_approval_policy).to be_zero
end
end
context 'when collections feature is enabled', feature: :collections do
it 'sets the interaction policy to the correct value' do it 'sets the interaction policy to the correct value' do
account = subject.call('user1', 'foo.test', payload) account = subject.call('user1', 'foo.test', payload)

View File

@ -30,7 +30,7 @@ RSpec.describe ResolveURLService do
expect(subject.call(url)).to eq known_account expect(subject.call(url)).to eq known_account
end end
context 'when searching for a remote collection', feature: :collections do context 'when searching for a remote collection' do
let(:account) { Fabricate(:account) } let(:account) { Fabricate(:account) }
let(:collection_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub) } let(:collection_account) { Fabricate(:account, domain: 'example.com', protocol: :activitypub) }
@ -63,7 +63,7 @@ RSpec.describe ResolveURLService do
end end
end end
context 'when searching for a local collection', feature: :collections do context 'when searching for a local collection' do
let(:account) { Fabricate(:account) } let(:account) { Fabricate(:account) }
let(:collection) { Fabricate(:collection) } let(:collection) { Fabricate(:collection) }