Skip to content

Commit 9c4945f

Browse files
committed
Fixes #39246 - Add sorting and searching to the new Leapp preupgrade report
1 parent 8c56131 commit 9c4945f

14 files changed

Lines changed: 667 additions & 221 deletions
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# frozen_string_literal: true
2+
3+
module Api
4+
module V2
5+
class PreupgradeReportEntriesController < ::Api::V2::BaseController
6+
include ApiAuthorizer
7+
8+
api :GET, '/preupgrade_reports/:preupgrade_report_id/preupgrade_report_entries',
9+
N_('List entries for a Preupgrade report')
10+
param :preupgrade_report_id, :identifier, required: true
11+
param :search, String, required: false, desc: N_('Filter entries')
12+
param :order, String, required: false, desc: N_('Sort entries, e.g. "title ASC"')
13+
param :page, :number, required: false, desc: N_('Page number')
14+
param :per_page, :number, required: false, desc: N_('Items per page')
15+
def index
16+
@total = resource_scope.count
17+
@preupgrade_report_entries = resource_scope_for_index
18+
@subtotal = @preupgrade_report_entries.total_entries
19+
end
20+
21+
protected
22+
23+
def resource_scope
24+
@preupgrade_report ||= PreupgradeReport.find(params[:preupgrade_report_id])
25+
@preupgrade_report.preupgrade_report_entries
26+
end
27+
end
28+
end
29+
end

app/controllers/api/v2/preupgrade_reports_controller.rb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@ def job_invocation
2727

2828
private
2929

30-
# By overriding path_to_authenticate we can require REX's permission view_job_invocations
3130
def path_to_authenticate
3231
params['action'] = 'show' if params['action'] == 'job_invocation'
33-
Foreman::AccessControl.normalize_path_hash params.slice(:action, :id, :user_id)
34-
.merge({ controller: 'api/v2/job_invocations' })
32+
path_params = params.slice(:action, :id, :user_id).merge(controller: 'api/v2/job_invocations')
33+
Foreman::AccessControl.normalize_path_hash(path_params)
3534
end
3635
end
3736
end
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# frozen_string_literal: true
2+
3+
class PreupgradeReportEntriesController < ApplicationController
4+
include Foreman::Controller::AutoCompleteSearch
5+
6+
# rubocop:disable Rails/LexicallyScopedActionFilter
7+
skip_before_action :authorize, only: %i[auto_complete_search]
8+
before_action :authorize_autocomplete, only: %i[auto_complete_search]
9+
# rubocop:enable Rails/LexicallyScopedActionFilter
10+
11+
protected
12+
13+
def model_of_controller
14+
PreupgradeReportEntry.joins(:host).merge(Host.authorized(:view_hosts, Host))
15+
end
16+
17+
def resource_scope
18+
model_of_controller
19+
end
20+
21+
private
22+
23+
def authorize_autocomplete
24+
unless User.current.can?('view_job_invocations')
25+
render json: {
26+
error: {
27+
message: _('Missing one of the required permissions: view_job_invocations'),
28+
missing_permissions: ['view_job_invocations'],
29+
},
30+
}, status: :forbidden
31+
return
32+
end
33+
34+
return if User.current.can?('view_hosts')
35+
36+
render json: {
37+
error: {
38+
message: _('Missing one of the required permissions: view_hosts'),
39+
missing_permissions: ['view_hosts'],
40+
},
41+
}, status: :forbidden
42+
end
43+
44+
def action_permission
45+
'view'
46+
end
47+
48+
def controller_permission
49+
'job_invocations'
50+
end
51+
end

app/models/preupgrade_report_entry.rb

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,62 @@ class PreupgradeReportEntry < ApplicationRecord
88
serialize :flags, Array
99
serialize :detail, JSON
1010

11-
validates :preupgrade_report, :host, :hostname, :title, :actor, :audience, :severity, :leapp_run_id, presence: true
11+
validates :preupgrade_report, :host, :hostname, :title, :actor,
12+
:audience, :severity, :leapp_run_id, presence: true
13+
14+
scoped_search on: :title, complete_value: true
15+
scoped_search on: :hostname, complete_value: true
16+
scoped_search on: :severity, complete_value: { high: 'high', medium: 'medium', low: 'low', info: 'info' }
17+
scoped_search on: :summary
18+
19+
scoped_search on: :flags,
20+
rename: :inhibitor,
21+
only_explicit: true,
22+
operators: ['=', '!='],
23+
complete_value: { yes: 'yes', no: 'no' },
24+
ext_method: :search_yes_no_fields
25+
26+
scoped_search on: :detail,
27+
rename: :has_remediation,
28+
only_explicit: true,
29+
operators: ['=', '!='],
30+
complete_value: { yes: 'yes', no: 'no' },
31+
ext_method: :search_yes_no_fields
32+
33+
scoped_search on: :detail,
34+
rename: :fix_type,
35+
only_explicit: true,
36+
operators: ['=', '!='],
37+
complete_value: { hint: 'hint', command: 'command' },
38+
ext_method: :search_fix_type
1239

1340
def self.remediation_details(remediation_ids, host)
1441
where(id: remediation_ids, host: host).where.not(detail: nil).pluck(:detail)
1542
end
43+
44+
def self.search_yes_no_fields(key, operator, value)
45+
column, term = case key.to_sym
46+
when :inhibitor then %w[flags inhibitor]
47+
when :has_remediation then %w[detail remediations]
48+
end
49+
50+
if (operator == '=' && value == 'yes') || (operator == '!=' && value == 'no')
51+
{ conditions: "preupgrade_report_entries.#{column} LIKE '%%#{term}%%'" }
52+
else
53+
{ conditions: "(preupgrade_report_entries.#{column} NOT LIKE '%%#{term}%%' OR " \
54+
"preupgrade_report_entries.#{column} IS NULL)" }
55+
end
56+
end
57+
58+
def self.search_fix_type(_key, operator, value)
59+
return {} unless %w[hint command].include?(value.to_s.downcase)
60+
61+
like_op = operator == '=' ? 'LIKE' : 'NOT LIKE'
62+
conditions = "(preupgrade_report_entries.detail #{like_op} '%%\"type\":\"#{value}\"%%' OR " \
63+
"preupgrade_report_entries.detail #{like_op} '%%\"type\": \"#{value}\"%%')"
64+
65+
conditions = "(#{conditions} OR preupgrade_report_entries.detail IS NULL)" if operator == '!='
66+
67+
{ conditions: conditions }
68+
end
1669
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
object false
4+
5+
child(@preupgrade_report_entries => :results) do
6+
extends 'api/v2/preupgrade_report_entries/main'
7+
end
8+
9+
node(:total) { @total }
10+
node(:subtotal) { @subtotal }
11+
node(:page) { params[:page].to_i.positive? ? params[:page].to_i : 1 }
12+
node(:per_page) { params[:per_page].to_i.positive? ? params[:per_page].to_i : Setting[:entries_per_page] }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# frozen_string_literal: true
2+
3+
extends 'api/v2/preupgrade_report_entries/base'
Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
object @preupgrade_report
2-
3-
extends 'api/v2/preupgrade_reports/base'
1+
# frozen_string_literal: true
42

5-
child :preupgrade_report_entries do
6-
extends 'api/v2/preupgrade_report_entries/base'
7-
end
3+
object @preupgrade_report
4+
attributes :id, :status, :reported_at

config/routes.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
# frozen_string_literal: true
22

33
Rails.application.routes.draw do
4-
resources :preupgrade_reports, :only => %i[index]
4+
resources :preupgrade_reports, only: %i[index]
5+
6+
resources :preupgrade_report_entries, only: [] do
7+
collection do
8+
get :auto_complete_search
9+
end
10+
end
511

612
namespace :api, defaults: { format: 'json' } do
713
scope '(:apiv)', module: :v2, defaults: { apiv: 'v2' }, apiv: /v2/,
8-
constraints: ApiConstraints.new( version: 2, default: true) do
9-
resources :preupgrade_reports, only: %i[index show]
14+
constraints: ApiConstraints.new(version: 2, default: true) do
15+
resources :preupgrade_reports, only: %i[index show] do
16+
resources :preupgrade_report_entries, only: %i[index]
17+
end
18+
1019
get 'job_invocations/:id/preupgrade_reports', to: 'preupgrade_reports#job_invocation'
1120
end
1221
end

test/functional/api/v2/preupgrade_reports_controller_test.rb

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
module Api
66
module V2
7+
# rubocop:disable Metrics/ClassLength
78
class PreupgradeReportsControllerTest < ActionController::TestCase
89
setup do
910
@host = FactoryBot.create(:host)
@@ -22,9 +23,9 @@ class PreupgradeReportsControllerTest < ActionController::TestCase
2223
get :show, params: { id: @report.id }
2324
assert_response :success
2425

25-
response = JSON.parse(@response.body)
26-
assert_equal response['id'], @report.id
27-
assert_not_empty response['preupgrade_report_entries']
26+
body = JSON.parse(@response.body)
27+
assert_equal @report.id, body['id']
28+
assert_nil body['results']
2829
end
2930

3031
test 'should get :job_invocation' do
@@ -49,7 +50,9 @@ class PreupgradeReportsControllerTest < ActionController::TestCase
4950
test 'should get :show' do
5051
get :show, params: { id: @report.id }, session: set_session_user(@user)
5152
assert_response :success
52-
assert_equal @report.id, JSON.parse(@response.body)['id']
53+
json = ActiveSupport::JSON.decode(@response.body)
54+
assert_equal @report.id, json['id']
55+
assert_nil json['results']
5356
end
5457

5558
test 'should get :job_invocation' do
@@ -96,7 +99,7 @@ class PreupgradeReportsControllerTest < ActionController::TestCase
9699
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
97100
end
98101

99-
test 'should not get :job_invocation' do
102+
test 'should not get :show' do
100103
get :show, params: { id: @report.id }, session: set_session_user(@user)
101104
assert_response :forbidden
102105
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
@@ -109,5 +112,6 @@ class PreupgradeReportsControllerTest < ActionController::TestCase
109112
end
110113
end
111114
end
115+
# rubocop:enable Metrics/ClassLength
112116
end
113117
end
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# frozen_string_literal: true
2+
3+
require 'test_plugin_helper'
4+
5+
class PreupgradeReportEntriesControllerTest < ActionController::TestCase
6+
setup do
7+
@user = FactoryBot.create(:user, admin: false)
8+
@host = FactoryBot.create(:host)
9+
@report = FactoryBot.create(:preupgrade_report, host: @host)
10+
@entry = FactoryBot.create(:preupgrade_report_entry, host: @host, preupgrade_report: @report)
11+
end
12+
13+
test 'should get auto_complete_search with required permissions' do
14+
User.any_instance.stubs(:can?).with('view_job_invocations').returns(true)
15+
User.any_instance.stubs(:can?).with('view_hosts').returns(true)
16+
17+
get :auto_complete_search, params: { format: :json }, session: set_session_user(@user)
18+
assert_response :success
19+
end
20+
21+
test 'should not get auto_complete_search without :view_hosts' do
22+
User.any_instance.stubs(:can?).with('view_job_invocations').returns(true)
23+
User.any_instance.stubs(:can?).with('view_hosts').returns(false)
24+
25+
get :auto_complete_search, params: { format: :json }, session: set_session_user(@user)
26+
assert_response :forbidden
27+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
28+
end
29+
30+
test 'should not get auto_complete_search without :view_job_invocations' do
31+
User.any_instance.stubs(:can?).with('view_job_invocations').returns(false)
32+
33+
get :auto_complete_search, params: { format: :json }, session: set_session_user(@user)
34+
assert_response :forbidden
35+
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_job_invocations'
36+
end
37+
end

0 commit comments

Comments
 (0)