Improve collection item behavior in REST API (#38732)
This commit is contained in:
parent
5722b1bbc5
commit
b846f88e16
@ -65,6 +65,7 @@ class Collection < ApplicationRecord
|
|||||||
|
|
||||||
def items_for(account = nil)
|
def items_for(account = nil)
|
||||||
result = collection_items.with_accounts
|
result = collection_items.with_accounts
|
||||||
|
result = account == self.account ? result.pending_or_accepted : result.accepted
|
||||||
result = result.not_blocked_by(account) unless account.nil?
|
result = result.not_blocked_by(account) unless account.nil?
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|||||||
@ -43,6 +43,7 @@ class CollectionItem < ApplicationRecord
|
|||||||
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) }
|
scope :local, -> { joins(:collection).merge(Collection.local) }
|
||||||
scope :accepted_partial, ->(account) { joins(:account).merge(Account.local).accepted.where(uri: nil, account_id: account.id) }
|
scope :accepted_partial, ->(account) { joins(:account).merge(Account.local).accepted.where(uri: nil, account_id: account.id) }
|
||||||
|
scope :pending_or_accepted, -> { where(state: [:pending, :accepted]) }
|
||||||
|
|
||||||
def revoke!
|
def revoke!
|
||||||
update!(state: :revoked)
|
update!(state: :revoked)
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class REST::CollectionItemSerializer < ActiveModel::Serializer
|
class REST::CollectionItemSerializer < ActiveModel::Serializer
|
||||||
delegate :accepted?, to: :object
|
|
||||||
|
|
||||||
attributes :id, :state, :created_at
|
attributes :id, :state, :created_at
|
||||||
|
|
||||||
attribute :account_id, if: :accepted?
|
attribute :account_id, if: :accepted_or_pending?
|
||||||
|
|
||||||
def id
|
def id
|
||||||
object.id.to_s
|
object.id.to_s
|
||||||
@ -14,4 +12,8 @@ class REST::CollectionItemSerializer < ActiveModel::Serializer
|
|||||||
def account_id
|
def account_id
|
||||||
object.account_id.to_s
|
object.account_id.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def accepted_or_pending?
|
||||||
|
object.pending? || object.accepted?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -29,7 +29,11 @@ class REST::CollectionSerializer < ActiveModel::Serializer
|
|||||||
end
|
end
|
||||||
|
|
||||||
def items
|
def items
|
||||||
object.items_for(current_user&.account)
|
@items ||= object.items_for(current_user&.account)
|
||||||
|
end
|
||||||
|
|
||||||
|
def item_count
|
||||||
|
items.size
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_id
|
def account_id
|
||||||
|
|||||||
@ -64,11 +64,18 @@ RSpec.describe Collection do
|
|||||||
describe '#item_for' do
|
describe '#item_for' do
|
||||||
subject { Fabricate(:collection) }
|
subject { Fabricate(:collection) }
|
||||||
|
|
||||||
let!(:items) { Fabricate.times(2, :collection_item, collection: subject) }
|
let!(:accepted_items) { Fabricate.times(2, :collection_item, collection: subject, state: :accepted) }
|
||||||
|
let!(:pending_item) { Fabricate(:collection_item, collection: subject, state: :pending) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
%i(rejected revoked).each do |state|
|
||||||
|
Fabricate(:collection_item, collection: subject, state:)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when given no account' do
|
context 'when given no account' do
|
||||||
it 'returns all items' do
|
it 'returns all accepted items' do
|
||||||
expect(subject.items_for).to match_array(items)
|
expect(subject.items_for).to match_array(accepted_items)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -76,11 +83,19 @@ RSpec.describe Collection do
|
|||||||
let(:account) { Fabricate(:account) }
|
let(:account) { Fabricate(:account) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
account.block!(items.first.account)
|
account.block!(accepted_items.first.account)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not return items blocked by this account' do
|
it 'does not return items blocked by this account' do
|
||||||
expect(subject.items_for(account)).to contain_exactly(items.last)
|
expect(subject.items_for(account)).to contain_exactly(accepted_items.last)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when given the owner of the collection' do
|
||||||
|
let(:account) { subject.account }
|
||||||
|
|
||||||
|
it 'returns accepted and pending items' do
|
||||||
|
expect(subject.items_for(account)).to match_array(accepted_items + [pending_item])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -11,23 +11,33 @@ RSpec.describe REST::CollectionItemSerializer do
|
|||||||
state:)
|
state:)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when state is `accepted`' do
|
shared_examples 'full result' do
|
||||||
let(:state) { :accepted }
|
|
||||||
|
|
||||||
it 'includes the relevant attributes including the account' do
|
it 'includes the relevant attributes including the account' do
|
||||||
expect(subject)
|
expect(subject)
|
||||||
.to include(
|
.to include(
|
||||||
'id' => '2342',
|
'id' => '2342',
|
||||||
'account_id' => collection_item.account_id.to_s,
|
'account_id' => collection_item.account_id.to_s,
|
||||||
'state' => 'accepted',
|
'state' => state.to_s,
|
||||||
'created_at' => match_api_datetime_format
|
'created_at' => match_api_datetime_format
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
%i(pending rejected revoked).each do |unaccepted_state|
|
context 'when state is `accepted`' do
|
||||||
context "when state is `#{unaccepted_state}`" do
|
let(:state) { :accepted }
|
||||||
let(:state) { unaccepted_state }
|
|
||||||
|
it_behaves_like 'full result'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when state is `pending`' do
|
||||||
|
let(:state) { :pending }
|
||||||
|
|
||||||
|
it_behaves_like 'full result'
|
||||||
|
end
|
||||||
|
|
||||||
|
%i(rejected revoked).each do |rejected_state|
|
||||||
|
context "when state is `#{rejected_state}`" do
|
||||||
|
let(:state) { rejected_state }
|
||||||
|
|
||||||
it 'does not include an account' do
|
it 'does not include an account' do
|
||||||
expect(subject.keys).to_not include('account_id')
|
expect(subject.keys).to_not include('account_id')
|
||||||
|
|||||||
@ -67,4 +67,30 @@ RSpec.describe REST::CollectionSerializer do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the collection has items in different states' do
|
||||||
|
before do
|
||||||
|
%i(accepted pending rejected revoked).each do |state|
|
||||||
|
Fabricate(:collection_item, collection:, state:)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when `current_user` is the owner of the collection' do
|
||||||
|
let(:current_user) { collection.account.user }
|
||||||
|
|
||||||
|
it 'includes accepted and pending items' do
|
||||||
|
expect(subject['item_count']).to eq 2
|
||||||
|
expect(subject['items'].size).to eq 2
|
||||||
|
expect(subject['items'].pluck('state')).to contain_exactly('accepted', 'pending')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when `current_user` is not the owner of the collection' do
|
||||||
|
it 'only includes the accepted item' do
|
||||||
|
expect(subject['item_count']).to eq 1
|
||||||
|
expect(subject['items'].size).to eq 1
|
||||||
|
expect(subject['items'].first['state']).to eq 'accepted'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user