FEATURE: Allow admins to delete reviewables via API (#21174)
This PR adds the ability to destroy reviewables for a passed user via the API. This was not possible before as this action was reserved for reviewables for you created only. If a user is an admin and calls the `#destroy` action from the API they are able to destroy a reviewable for a passed user. A user can be targeted by passed either their: - username - external_id (for SSO) to the request. In the case you attempt to destroy a non-personal reviewable and - You are not an admin - You do not access the `#destroy` action via the API you will raise a `Discourse::InvalidAccess` (403) and will not succeed in destroying the reviewable.
This commit is contained in:
parent
ba2adc7793
commit
dd495a0e19
|
@ -155,7 +155,18 @@ class ReviewablesController < ApplicationController
|
|||
end
|
||||
|
||||
def destroy
|
||||
reviewable = Reviewable.find_by(id: params[:reviewable_id], created_by: current_user)
|
||||
user =
|
||||
if is_api?
|
||||
if @guardian.is_admin?
|
||||
fetch_user_from_params
|
||||
else
|
||||
raise Discourse::InvalidAccess
|
||||
end
|
||||
else
|
||||
current_user
|
||||
end
|
||||
|
||||
reviewable = Reviewable.find_by(id: params[:reviewable_id], created_by: user)
|
||||
raise Discourse::NotFound.new if reviewable.blank?
|
||||
|
||||
reviewable.perform(current_user, :delete)
|
||||
|
|
|
@ -232,7 +232,7 @@ class Guardian
|
|||
end
|
||||
|
||||
def can_delete_reviewable_queued_post?(reviewable)
|
||||
reviewable.present? && authenticated? && reviewable.created_by_id == @user.id
|
||||
reviewable.present? && authenticated? && (reviewable.created_by_id == @user.id || @user.admin?)
|
||||
end
|
||||
|
||||
def can_see_group?(group)
|
||||
|
|
|
@ -790,25 +790,94 @@ RSpec.describe ReviewablesController do
|
|||
describe "#destroy" do
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
|
||||
before { sign_in(user) }
|
||||
|
||||
it "returns 404 if the reviewable doesn't exist" do
|
||||
sign_in(user)
|
||||
delete "/review/1234.json"
|
||||
expect(response.code).to eq("404")
|
||||
end
|
||||
|
||||
it "returns 404 if the user can't see the reviewable" do
|
||||
sign_in(user)
|
||||
queued_post = Fabricate(:reviewable_queued_post)
|
||||
delete "/review/#{queued_post.id}.json"
|
||||
expect(response.code).to eq("404")
|
||||
end
|
||||
|
||||
it "returns 200 if the user can delete the reviewable" do
|
||||
sign_in(user)
|
||||
queued_post = Fabricate(:reviewable_queued_post, created_by: user)
|
||||
delete "/review/#{queued_post.id}.json"
|
||||
expect(response.code).to eq("200")
|
||||
expect(queued_post.reload).to be_deleted
|
||||
end
|
||||
|
||||
it "denies attempts to destroy unowned reviewables" do
|
||||
sign_in(admin)
|
||||
queued_post = Fabricate(:reviewable_queued_post, created_by: user)
|
||||
delete "/review/#{queued_post.id}.json"
|
||||
expect(response.status).to eq(404)
|
||||
# Reviewable is not deleted because request is not via API
|
||||
expect(queued_post.reload).to be_present
|
||||
end
|
||||
|
||||
shared_examples "for a passed user" do
|
||||
it "deletes reviewable" do
|
||||
api_key = Fabricate(:api_key).key
|
||||
queued_post = Fabricate(:reviewable_queued_post, created_by: recipient)
|
||||
delete "/review/#{queued_post.id}.json",
|
||||
params: {
|
||||
username: recipient.username,
|
||||
},
|
||||
headers: {
|
||||
HTTP_API_USERNAME: caller.username,
|
||||
HTTP_API_KEY: api_key,
|
||||
}
|
||||
|
||||
expect(response.status).to eq(response_code)
|
||||
|
||||
if reviewable_deleted
|
||||
expect(queued_post.reload).to be_deleted
|
||||
else
|
||||
expect(queued_post.reload).to be_present
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "api called by admin" do
|
||||
include_examples "for a passed user" do
|
||||
let(:caller) { Fabricate(:admin) }
|
||||
let(:recipient) { user }
|
||||
let(:response_code) { 200 }
|
||||
let(:reviewable_deleted) { true }
|
||||
end
|
||||
end
|
||||
|
||||
describe "api called by tl4 user" do
|
||||
include_examples "for a passed user" do
|
||||
let(:caller) { Fabricate(:trust_level_4) }
|
||||
let(:recipient) { user }
|
||||
let(:response_code) { 403 }
|
||||
let(:reviewable_deleted) { false }
|
||||
end
|
||||
end
|
||||
|
||||
describe "api called by regular user" do
|
||||
include_examples "for a passed user" do
|
||||
let(:caller) { user }
|
||||
let(:recipient) { Fabricate(:user) }
|
||||
let(:response_code) { 403 }
|
||||
let(:reviewable_deleted) { false }
|
||||
end
|
||||
end
|
||||
|
||||
describe "api called by admin for another admin" do
|
||||
include_examples "for a passed user" do
|
||||
let(:caller) { Fabricate(:admin) }
|
||||
let(:recipient) { Fabricate(:admin) }
|
||||
let(:response_code) { 200 }
|
||||
let(:reviewable_deleted) { true }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#count" do
|
||||
|
|
Loading…
Reference in New Issue