mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
FEATURE: Extend topic update API scope to allow status updates (#19654)
Allow an API key created with topic:update API scope to make updates to topic status. This change also introduces an optional category_id scope param.
This commit is contained in:
parent
8a1b50f62d
commit
73ec80893d
@ -479,7 +479,12 @@ class TopicsController < ApplicationController
|
|||||||
enabled = params[:enabled] == "true"
|
enabled = params[:enabled] == "true"
|
||||||
|
|
||||||
check_for_status_presence(:status, status)
|
check_for_status_presence(:status, status)
|
||||||
@topic = Topic.find_by(id: topic_id)
|
@topic =
|
||||||
|
if params[:category_id]
|
||||||
|
Topic.find_by(id: topic_id, category_id: params[:category_id].to_i)
|
||||||
|
else
|
||||||
|
Topic.find_by(id: topic_id)
|
||||||
|
end
|
||||||
|
|
||||||
case status
|
case status
|
||||||
when "closed"
|
when "closed"
|
||||||
|
@ -28,8 +28,8 @@ class ApiKeyScope < ActiveRecord::Base
|
|||||||
params: %i[topic_id],
|
params: %i[topic_id],
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
actions: %w[topics#update],
|
actions: %w[topics#update topics#status],
|
||||||
params: %i[topic_id],
|
params: %i[topic_id category_id],
|
||||||
},
|
},
|
||||||
read: {
|
read: {
|
||||||
actions: %w[topics#show topics#feed topics#posts],
|
actions: %w[topics#show topics#feed topics#posts],
|
||||||
|
@ -4670,7 +4670,7 @@ en:
|
|||||||
topics:
|
topics:
|
||||||
read: Read a topic or a specific post in it. RSS is also supported.
|
read: Read a topic or a specific post in it. RSS is also supported.
|
||||||
write: Create a new topic or post to an existing one.
|
write: Create a new topic or post to an existing one.
|
||||||
update: Update a topic. Change the title, category, tags, etc.
|
update: Update a topic. Change the title, category, tags, status, archetype, featured_link etc.
|
||||||
read_lists: Read topic lists like top, new, latest, etc. RSS is also supported.
|
read_lists: Read topic lists like top, new, latest, etc. RSS is also supported.
|
||||||
posts:
|
posts:
|
||||||
edit: Edit any post or a specific one.
|
edit: Edit any post or a specific one.
|
||||||
|
@ -59,7 +59,7 @@ class RouteMatcher
|
|||||||
|
|
||||||
params.all? do |param|
|
params.all? do |param|
|
||||||
param_alias = aliases&.[](param)
|
param_alias = aliases&.[](param)
|
||||||
allowed_values = [allowed_param_values[param.to_s]].flatten
|
allowed_values = [allowed_param_values.fetch(param.to_s, [])].flatten
|
||||||
|
|
||||||
value = requested_params[param.to_s]
|
value = requested_params[param.to_s]
|
||||||
alias_value = requested_params[param_alias.to_s]
|
alias_value = requested_params[param_alias.to_s]
|
||||||
|
@ -1037,6 +1037,99 @@ RSpec.describe TopicsController do
|
|||||||
expect(topic.posts.last.action_code).to eq("visible.enabled")
|
expect(topic.posts.last.action_code).to eq("visible.enabled")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with API key" do
|
||||||
|
let(:api_key) { Fabricate(:api_key, user: moderator, created_by: moderator) }
|
||||||
|
|
||||||
|
context "when key scope has restricted params" do
|
||||||
|
before do
|
||||||
|
ApiKeyScope.create(
|
||||||
|
resource: "topics",
|
||||||
|
action: "update",
|
||||||
|
api_key_id: api_key.id,
|
||||||
|
allowed_parameters: {
|
||||||
|
"category_id" => ["#{topic.category_id}"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails to update topic status in an unpermitted category" do
|
||||||
|
put "/t/#{topic.id}/status.json",
|
||||||
|
params: {
|
||||||
|
status: "closed",
|
||||||
|
enabled: "true",
|
||||||
|
category_id: tracked_category.id,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
"HTTP_API_KEY" => api_key.key,
|
||||||
|
"HTTP_API_USERNAME" => api_key.user.username,
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
expect(response.body).to include(I18n.t("invalid_access"))
|
||||||
|
expect(topic.reload.closed).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "fails without a category_id" do
|
||||||
|
put "/t/#{topic.id}/status.json",
|
||||||
|
params: {
|
||||||
|
status: "closed",
|
||||||
|
enabled: "true",
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
"HTTP_API_KEY" => api_key.key,
|
||||||
|
"HTTP_API_USERNAME" => api_key.user.username,
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
expect(response.body).to include(I18n.t("invalid_access"))
|
||||||
|
expect(topic.reload.closed).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "updates topic status in a permitted category" do
|
||||||
|
put "/t/#{topic.id}/status.json",
|
||||||
|
params: {
|
||||||
|
status: "closed",
|
||||||
|
enabled: "true",
|
||||||
|
category_id: topic.category_id,
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
"HTTP_API_KEY" => api_key.key,
|
||||||
|
"HTTP_API_USERNAME" => api_key.user.username,
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(topic.reload.closed).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when key scope has no param restrictions" do
|
||||||
|
before do
|
||||||
|
ApiKeyScope.create(
|
||||||
|
resource: "topics",
|
||||||
|
action: "update",
|
||||||
|
api_key_id: api_key.id,
|
||||||
|
allowed_parameters: {
|
||||||
|
},
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "updates topic status" do
|
||||||
|
put "/t/#{topic.id}/status.json",
|
||||||
|
params: {
|
||||||
|
status: "closed",
|
||||||
|
enabled: "true",
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
"HTTP_API_KEY" => api_key.key,
|
||||||
|
"HTTP_API_USERNAME" => api_key.user.username,
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(topic.reload.closed).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#destroy_timings" do
|
describe "#destroy_timings" do
|
||||||
|
Loading…
Reference in New Issue
Block a user