diff --git a/app/controllers/api/v1_alpha/collection_items_controller.rb b/app/controllers/api/v1_alpha/collection_items_controller.rb index 5c78de14e95..2c46cc4f9fc 100644 --- a/app/controllers/api/v1_alpha/collection_items_controller.rb +++ b/app/controllers/api/v1_alpha/collection_items_controller.rb @@ -11,7 +11,7 @@ class Api::V1Alpha::CollectionItemsController < Api::BaseController before_action :set_collection before_action :set_account, only: [:create] - before_action :set_collection_item, only: [:destroy] + before_action :set_collection_item, only: [:destroy, :revoke] after_action :verify_authorized @@ -32,6 +32,14 @@ class Api::V1Alpha::CollectionItemsController < Api::BaseController head 200 end + def revoke + authorize @collection_item, :revoke? + + RevokeCollectionItemService.new.call(@collection_item) + + head 200 + end + private def set_collection diff --git a/app/policies/collection_item_policy.rb b/app/policies/collection_item_policy.rb new file mode 100644 index 00000000000..73552a3b8a1 --- /dev/null +++ b/app/policies/collection_item_policy.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class CollectionItemPolicy < ApplicationPolicy + def revoke? + featured_account.present? && current_account == featured_account + end + + private + + def featured_account + record.account + end +end diff --git a/config/routes/api.rb b/config/routes/api.rb index 5322f15c8f0..285b032d01f 100644 --- a/config/routes/api.rb +++ b/config/routes/api.rb @@ -13,7 +13,11 @@ namespace :api, format: false do resources :async_refreshes, only: :show resources :collections, only: [:show, :create, :update, :destroy] do - resources :items, only: [:create, :destroy], controller: 'collection_items' + resources :items, only: [:create, :destroy], controller: 'collection_items' do + member do + post :revoke + end + end end end diff --git a/spec/policies/collection_item_policy_spec.rb b/spec/policies/collection_item_policy_spec.rb new file mode 100644 index 00000000000..d12384209e4 --- /dev/null +++ b/spec/policies/collection_item_policy_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe CollectionItemPolicy do + subject { described_class } + + let(:account) { Fabricate(:account) } + + permissions :revoke? do + context 'when collection item features the revoking account' do + let(:collection_item) { Fabricate.build(:collection_item, account:) } + + it { is_expected.to permit(account, collection_item) } + end + + context 'when collection item does not feature the revoking account' do + let(:collection_item) { Fabricate.build(:collection_item) } + + it { is_expected.to_not permit(account, collection_item) } + end + end +end diff --git a/spec/requests/api/v1_alpha/collection_items_spec.rb b/spec/requests/api/v1_alpha/collection_items_spec.rb index 6d33e6a7113..e7ee854e67a 100644 --- a/spec/requests/api/v1_alpha/collection_items_spec.rb +++ b/spec/requests/api/v1_alpha/collection_items_spec.rb @@ -102,4 +102,35 @@ RSpec.describe 'Api::V1Alpha::CollectionItems', feature: :collections do end end end + + describe 'POST /api/v1_alpha/collections/:collection_id/items/:id/revoke' do + subject do + post "/api/v1_alpha/collections/#{collection.id}/items/#{item.id}/revoke", headers: headers + end + + let(:collection) { Fabricate(:collection) } + let(:item) { Fabricate(:collection_item, collection:, account: user.account) } + + it_behaves_like 'forbidden for wrong scope', 'read' + + context 'when user is in item' do + it 'revokes the collection item and returns http success' do + subject + + expect(item.reload).to be_revoked + + expect(response).to have_http_status(200) + end + end + + context 'when user is not in the item' do + let(:item) { Fabricate(:collection_item, collection:) } + + it 'returns http forbidden' do + subject + + expect(response).to have_http_status(403) + end + end + end end