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
|
end
|
||||||
|
|
||||||
def destroy
|
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?
|
raise Discourse::NotFound.new if reviewable.blank?
|
||||||
|
|
||||||
reviewable.perform(current_user, :delete)
|
reviewable.perform(current_user, :delete)
|
||||||
|
|
|
@ -232,7 +232,7 @@ class Guardian
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_delete_reviewable_queued_post?(reviewable)
|
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
|
end
|
||||||
|
|
||||||
def can_see_group?(group)
|
def can_see_group?(group)
|
||||||
|
|
|
@ -790,25 +790,94 @@ RSpec.describe ReviewablesController do
|
||||||
describe "#destroy" do
|
describe "#destroy" do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
before { sign_in(user) }
|
|
||||||
|
|
||||||
it "returns 404 if the reviewable doesn't exist" do
|
it "returns 404 if the reviewable doesn't exist" do
|
||||||
|
sign_in(user)
|
||||||
delete "/review/1234.json"
|
delete "/review/1234.json"
|
||||||
expect(response.code).to eq("404")
|
expect(response.code).to eq("404")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns 404 if the user can't see the reviewable" do
|
it "returns 404 if the user can't see the reviewable" do
|
||||||
|
sign_in(user)
|
||||||
queued_post = Fabricate(:reviewable_queued_post)
|
queued_post = Fabricate(:reviewable_queued_post)
|
||||||
delete "/review/#{queued_post.id}.json"
|
delete "/review/#{queued_post.id}.json"
|
||||||
expect(response.code).to eq("404")
|
expect(response.code).to eq("404")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns 200 if the user can delete the reviewable" do
|
it "returns 200 if the user can delete the reviewable" do
|
||||||
|
sign_in(user)
|
||||||
queued_post = Fabricate(:reviewable_queued_post, created_by: user)
|
queued_post = Fabricate(:reviewable_queued_post, created_by: user)
|
||||||
delete "/review/#{queued_post.id}.json"
|
delete "/review/#{queued_post.id}.json"
|
||||||
expect(response.code).to eq("200")
|
expect(response.code).to eq("200")
|
||||||
expect(queued_post.reload).to be_deleted
|
expect(queued_post.reload).to be_deleted
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
describe "#count" do
|
describe "#count" do
|
||||||
|
|
Loading…
Reference in New Issue