FIX: Change request method for categories/search (#26976)

This commit changes request method for "categories/search" from GET to
POST to make sure that long filters can be passed to the server. For
example, category selectors with many categories are setting the full
list of selected category IDs to ensure these are filtered out from the
list of choices. This can result in a long URL that exceeds the maximum
length.
This commit is contained in:
Bianca Nenciu 2024-05-13 14:37:17 +03:00 committed by GitHub
parent 262393282d
commit ebc1763aa5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 25 additions and 24 deletions

View File

@ -403,7 +403,7 @@ export default class Category extends RestModel {
}; };
const result = (CATEGORY_ASYNC_SEARCH_CACHE[JSON.stringify(data)] ||= const result = (CATEGORY_ASYNC_SEARCH_CACHE[JSON.stringify(data)] ||=
await ajax("/categories/search", { data })); await ajax("/categories/search", { method: "POST", data }));
if (opts.includeAncestors) { if (opts.includeAncestors) {
return { return {

View File

@ -91,7 +91,7 @@ acceptance("Sidebar - Logged on user - Categories Section", function (needs) {
return helper.response(cloneJSON(categoryFixture["/c/1/show.json"])); return helper.response(cloneJSON(categoryFixture["/c/1/show.json"]));
}); });
server.get("/categories/search", () => { server.post("/categories/search", () => {
return helper.response({ categories: [], ancestors: [] }); return helper.response({ categories: [], ancestors: [] });
}); });
}); });

View File

@ -1169,7 +1169,7 @@ Discourse::Application.routes.draw do
resources :categories, except: %i[show new edit] resources :categories, except: %i[show new edit]
post "categories/reorder" => "categories#reorder" post "categories/reorder" => "categories#reorder"
get "categories/find" => "categories#find" get "categories/find" => "categories#find"
get "categories/search" => "categories#search" post "categories/search" => "categories#search"
scope path: "category/:category_id" do scope path: "category/:category_id" do
post "/move" => "categories#move" post "/move" => "categories#move"

View File

@ -52,6 +52,7 @@ module ReadOnlyMixin
def block_if_readonly_mode def block_if_readonly_mode
return if request.fullpath.start_with?(path "/admin/backups") return if request.fullpath.start_with?(path "/admin/backups")
return if request.fullpath.start_with?(path "/categories/search")
return if request.get? || request.head? return if request.get? || request.head?
if @staff_writes_only_mode if @staff_writes_only_mode

View File

@ -1211,9 +1211,9 @@ RSpec.describe CategoriesController do
category2.upsert_custom_fields("bob" => "marley") category2.upsert_custom_fields("bob" => "marley")
# Warm up caches # Warm up caches
get "/categories/search.json", params: { term: "Notfoo" } post "/categories/search.json", params: { term: "Notfoo" }
queries = track_sql_queries { get "/categories/search.json", params: { term: "Notfoo" } } queries = track_sql_queries { post "/categories/search.json", params: { term: "Notfoo" } }
expect(queries.length).to eq(8) expect(queries.length).to eq(8)
@ -1225,7 +1225,7 @@ RSpec.describe CategoriesController do
context "without include_ancestors" do context "without include_ancestors" do
it "doesn't return ancestors" do it "doesn't return ancestors" do
get "/categories/search.json", params: { term: "Notfoo" } post "/categories/search.json", params: { term: "Notfoo" }
expect(response.parsed_body).not_to have_key("ancestors") expect(response.parsed_body).not_to have_key("ancestors")
end end
@ -1233,7 +1233,7 @@ RSpec.describe CategoriesController do
context "with include_ancestors=false" do context "with include_ancestors=false" do
it "returns ancestors" do it "returns ancestors" do
get "/categories/search.json", params: { term: "Notfoo", include_ancestors: false } post "/categories/search.json", params: { term: "Notfoo", include_ancestors: false }
expect(response.parsed_body).not_to have_key("ancestors") expect(response.parsed_body).not_to have_key("ancestors")
end end
@ -1241,7 +1241,7 @@ RSpec.describe CategoriesController do
context "with include_ancestors=true" do context "with include_ancestors=true" do
it "returns ancestors" do it "returns ancestors" do
get "/categories/search.json", params: { term: "Notfoo", include_ancestors: true } post "/categories/search.json", params: { term: "Notfoo", include_ancestors: true }
expect(response.parsed_body).to have_key("ancestors") expect(response.parsed_body).to have_key("ancestors")
end end
@ -1249,7 +1249,7 @@ RSpec.describe CategoriesController do
context "with term" do context "with term" do
it "returns categories" do it "returns categories" do
get "/categories/search.json", params: { term: "Foo" } post "/categories/search.json", params: { term: "Foo" }
expect(response.parsed_body["categories"].size).to eq(3) expect(response.parsed_body["categories"].size).to eq(3)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1262,7 +1262,7 @@ RSpec.describe CategoriesController do
context "with parent_category_id" do context "with parent_category_id" do
it "returns categories" do it "returns categories" do
get "/categories/search.json", params: { parent_category_id: category.id } post "/categories/search.json", params: { parent_category_id: category.id }
expect(response.parsed_body["categories"].size).to eq(1) expect(response.parsed_body["categories"].size).to eq(1)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1271,7 +1271,7 @@ RSpec.describe CategoriesController do
end end
it "can return only top-level categories" do it "can return only top-level categories" do
get "/categories/search.json", params: { parent_category_id: -1 } post "/categories/search.json", params: { parent_category_id: -1 }
expect(response.parsed_body["categories"].size).to eq(3) expect(response.parsed_body["categories"].size).to eq(3)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1284,7 +1284,7 @@ RSpec.describe CategoriesController do
context "with include_uncategorized" do context "with include_uncategorized" do
it "returns Uncategorized" do it "returns Uncategorized" do
get "/categories/search.json", params: { include_uncategorized: true } post "/categories/search.json", params: { include_uncategorized: true }
expect(response.parsed_body["categories"].size).to eq(4) expect(response.parsed_body["categories"].size).to eq(4)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1296,7 +1296,7 @@ RSpec.describe CategoriesController do
end end
it "does not return Uncategorized" do it "does not return Uncategorized" do
get "/categories/search.json", params: { include_uncategorized: false } post "/categories/search.json", params: { include_uncategorized: false }
expect(response.parsed_body["categories"].size).to eq(3) expect(response.parsed_body["categories"].size).to eq(3)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1309,14 +1309,14 @@ RSpec.describe CategoriesController do
context "with select_category_ids" do context "with select_category_ids" do
it "returns categories" do it "returns categories" do
get "/categories/search.json", params: { select_category_ids: [category.id] } post "/categories/search.json", params: { select_category_ids: [category.id] }
expect(response.parsed_body["categories"].size).to eq(1) expect(response.parsed_body["categories"].size).to eq(1)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly("Foo") expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly("Foo")
end end
it "works with empty categories list" do it "works with empty categories list" do
get "/categories/search.json", params: { select_category_ids: [""] } post "/categories/search.json", params: { select_category_ids: [""] }
expect(response.parsed_body["categories"].size).to eq(0) expect(response.parsed_body["categories"].size).to eq(0)
end end
@ -1324,7 +1324,7 @@ RSpec.describe CategoriesController do
context "with reject_category_ids" do context "with reject_category_ids" do
it "returns categories" do it "returns categories" do
get "/categories/search.json", params: { reject_category_ids: [category2.id] } post "/categories/search.json", params: { reject_category_ids: [category2.id] }
expect(response.parsed_body["categories"].size).to eq(3) expect(response.parsed_body["categories"].size).to eq(3)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1335,7 +1335,7 @@ RSpec.describe CategoriesController do
end end
it "works with empty categories list" do it "works with empty categories list" do
get "/categories/search.json", params: { reject_category_ids: [""] } post "/categories/search.json", params: { reject_category_ids: [""] }
expect(response.parsed_body["categories"].size).to eq(4) expect(response.parsed_body["categories"].size).to eq(4)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1349,7 +1349,7 @@ RSpec.describe CategoriesController do
context "with include_subcategories" do context "with include_subcategories" do
it "returns categories" do it "returns categories" do
get "/categories/search.json", params: { include_subcategories: false } post "/categories/search.json", params: { include_subcategories: false }
expect(response.parsed_body["categories"].size).to eq(3) expect(response.parsed_body["categories"].size).to eq(3)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1360,7 +1360,7 @@ RSpec.describe CategoriesController do
end end
it "returns categories and subcategories" do it "returns categories and subcategories" do
get "/categories/search.json", params: { include_subcategories: true } post "/categories/search.json", params: { include_subcategories: true }
expect(response.parsed_body["categories"].size).to eq(4) expect(response.parsed_body["categories"].size).to eq(4)
expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly( expect(response.parsed_body["categories"].map { |c| c["name"] }).to contain_exactly(
@ -1374,7 +1374,7 @@ RSpec.describe CategoriesController do
context "with prioritized_category_id" do context "with prioritized_category_id" do
it "returns categories" do it "returns categories" do
get "/categories/search.json", params: { prioritized_category_id: category2.id } post "/categories/search.json", params: { prioritized_category_id: category2.id }
expect(response.parsed_body["categories"].size).to eq(4) expect(response.parsed_body["categories"].size).to eq(4)
expect(response.parsed_body["categories"][0]["name"]).to eq("Notfoo") expect(response.parsed_body["categories"][0]["name"]).to eq("Notfoo")
@ -1383,7 +1383,7 @@ RSpec.describe CategoriesController do
context "with limit" do context "with limit" do
it "returns categories" do it "returns categories" do
get "/categories/search.json", params: { limit: 2 } post "/categories/search.json", params: { limit: 2 }
expect(response.parsed_body["categories"].size).to eq(2) expect(response.parsed_body["categories"].size).to eq(2)
end end
@ -1402,7 +1402,7 @@ RSpec.describe CategoriesController do
end end
it "returns in correct order" do it "returns in correct order" do
get "/categories/search.json", params: { term: "ordered" } post "/categories/search.json", params: { term: "ordered" }
expect(response.parsed_body["categories"].map { |c| c["id"] }).to eq( expect(response.parsed_body["categories"].map { |c| c["id"] }).to eq(
[category4.id, category2.id, category3.id, category1.id], [category4.id, category2.id, category3.id, category1.id],
@ -1412,7 +1412,7 @@ RSpec.describe CategoriesController do
it "returns categories in the correct order when the limit is lower than the total number of categories" do it "returns categories in the correct order when the limit is lower than the total number of categories" do
categories = categories =
4.times.flat_map do |i| 4.times.flat_map do |i|
get "/categories/search.json", params: { term: "ordered", page: i + 1, limit: 1 } post "/categories/search.json", params: { term: "ordered", page: i + 1, limit: 1 }
response.parsed_body["categories"] response.parsed_body["categories"]
end end
@ -1425,7 +1425,7 @@ RSpec.describe CategoriesController do
it "returns user fields" do it "returns user fields" do
sign_in(admin) sign_in(admin)
get "/categories/search.json", params: { select_category_ids: [category.id] } post "/categories/search.json", params: { select_category_ids: [category.id] }
category = response.parsed_body["categories"].first category = response.parsed_body["categories"].first
expect(category["notification_level"]).to eq(NotificationLevels.all[:regular]) expect(category["notification_level"]).to eq(NotificationLevels.all[:regular])