FIX: Include engine mount path for API scopes added by plugins (#16154)

In the API keys page where admins can create API keys with restricted scopes, each scope shows a list of URLs that it allows. But currently, this list of allowed URLs shows incomplete URLs for scopes that are added by plugins. For example, the allowed URL for the "run queries" scope of the data-explorer plugin is shown as `/queries/:id/run` when the correct URL for this scope is `/admin/plugins/explorer/queries/:id/run`. The first 3 segments of the path are the mount path of the plugin's engine and it's missing because the routes set of the engine doesn't include the mount path. To fix this, this commit gets the mount path and prepends it to the URL so the complete URL is shown to the user.

It's not possible to write tests for this change because plugins are not loaded in the test environment by default when core's tests suite is running.
This commit is contained in:
Osama Sayegh 2022-03-10 22:01:22 +03:00 committed by GitHub
parent 93407005b5
commit 8d96761a4f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 14 additions and 10 deletions

View File

@ -106,22 +106,26 @@ class ApiKeyScope < ActiveRecord::Base
urls = []
if actions.present?
routes = Rails.application.routes.routes.to_a
route_sets = [Rails.application.routes]
Rails::Engine.descendants.each do |engine|
next if engine == Rails::Application # abstract engine, can't call routes on it
next if engine == Discourse::Application # equiv. to Rails.application
routes.concat(engine.routes.routes.to_a)
route_sets << engine.routes
end
routes.each do |route|
defaults = route.defaults
action = "#{defaults[:controller].to_s}##{defaults[:action]}"
path = route.path.spec.to_s.gsub(/\(\.:format\)/, '')
api_supported_path = path.end_with?('.rss') || route.path.requirements[:format]&.match?('json')
excluded_paths = %w[/new-topic /new-message /exception]
route_sets.each do |set|
engine_mount_path = set.find_script_name({}).presence
engine_mount_path = nil if engine_mount_path == "/"
set.routes.each do |route|
defaults = route.defaults
action = "#{defaults[:controller].to_s}##{defaults[:action]}"
path = route.path.spec.to_s.gsub(/\(\.:format\)/, '')
api_supported_path = path.end_with?('.rss') || route.path.requirements[:format]&.match?('json')
excluded_paths = %w[/new-topic /new-message /exception]
if actions.include?(action) && api_supported_path && !excluded_paths.include?(path)
urls << "#{path} (#{route.verb})"
if actions.include?(action) && api_supported_path && !excluded_paths.include?(path)
urls << "#{engine_mount_path}#{path} (#{route.verb})"
end
end
end
end