Skip to content

Commit 7f9dd42

Browse files
committed
Fixes #39246 - Add sorting and searching to the new Leapp preupgrade report
1 parent 3b9373e commit 7f9dd42

13 files changed

Lines changed: 617 additions & 203 deletions

File tree

app/controllers/api/v2/preupgrade_reports_controller.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,17 @@ def index
1515

1616
api :GET, '/preupgrade_reports/:id', N_('Show Preupgrade report')
1717
param :id, :identifier, required: true
18+
param :search, String, required: false, desc: N_('Filter entries')
19+
param :order, String, required: false, desc: N_('Sort entries, e.g. "title ASC"')
20+
param :page, :number, required: false, desc: N_('Page number')
21+
param :per_page, :number, required: false, desc: N_('Items per page')
1822
def show
1923
@preupgrade_report = resource_scope.find(params[:id])
24+
scope = @preupgrade_report.preupgrade_report_entries
25+
@entries = scope.search_for(params[:search], order: params[:order])
26+
.paginate(paginate_options)
27+
@total = scope.count
28+
@subtotal = @entries.total_entries
2029
end
2130

2231
api :GET, '/job_invocations/:id/preupgrade_reports', N_('List Preupgrade reports for Job invocation')
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# frozen_string_literal: true
2+
3+
class PreupgradeReportEntriesController < ApplicationController
4+
include Foreman::Controller::AutoCompleteSearch
5+
6+
skip_before_action :authorize, only: [:auto_complete_search]
7+
before_action :authorize_autocomplete, only: [:auto_complete_search]
8+
9+
def index
10+
@preupgrade_report_entries = resource_scope
11+
.search_for(params[:search], order: params[:order])
12+
.paginate(paginate_options)
13+
render 'api/v2/preupgrade_report_entries/index'
14+
end
15+
16+
protected
17+
18+
def model_of_controller
19+
PreupgradeReportEntry.joins(:host).merge(Host.authorized(:view_hosts, Host))
20+
end
21+
22+
def resource_scope
23+
model_of_controller
24+
end
25+
26+
private
27+
28+
def authorize_autocomplete
29+
unless User.current.can?('view_job_invocations')
30+
render json: { error: { message: _('Missing one of the required permissions: view_job_invocations'),
31+
missing_permissions: ['view_job_invocations'] } },
32+
status: :forbidden
33+
return
34+
end
35+
36+
unless User.current.can?('view_hosts')
37+
render json: { error: { message: _('Missing one of the required permissions: view_hosts'),
38+
missing_permissions: ['view_hosts'] } },
39+
status: :forbidden
40+
end
41+
end
42+
43+
def action_permission
44+
'view'
45+
end
46+
47+
def controller_permission
48+
'job_invocations'
49+
end
50+
end

app/models/preupgrade_report_entry.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,39 @@ class PreupgradeReportEntry < ApplicationRecord
1010

1111
validates :preupgrade_report, :host, :hostname, :title, :actor, :audience, :severity, :leapp_run_id, presence: true
1212

13+
scoped_search on: :title, complete_value: true
14+
scoped_search on: :hostname, complete_value: true
15+
scoped_search on: :severity, complete_value: { high: 'high', medium: 'medium', low: 'low', info: 'info' }
16+
scoped_search on: :summary
17+
18+
scoped_search on: :flags,
19+
rename: :inhibitor,
20+
only_explicit: true,
21+
operators: ['=', '!='],
22+
complete_value: { yes: 'yes', no: 'no' },
23+
ext_method: :search_yes_no_fields
24+
25+
scoped_search on: :detail,
26+
rename: :has_remediation,
27+
only_explicit: true,
28+
operators: ['=', '!='],
29+
complete_value: { yes: 'yes', no: 'no' },
30+
ext_method: :search_yes_no_fields
31+
1332
def self.remediation_details(remediation_ids, host)
1433
where(id: remediation_ids, host: host).where.not(detail: nil).pluck(:detail)
1534
end
35+
36+
def self.search_yes_no_fields(key, operator, value)
37+
column, term = case key.to_sym
38+
when :inhibitor then ['flags', 'inhibitor']
39+
when :has_remediation then ['detail', 'remediations']
40+
end
41+
42+
if (operator == '=' && value == 'yes') || (operator == '!=' && value == 'no')
43+
{ conditions: "preupgrade_report_entries.#{column} LIKE '%%#{term}%%'" }
44+
else
45+
{ conditions: "(preupgrade_report_entries.#{column} NOT LIKE '%%#{term}%%' OR preupgrade_report_entries.#{column} IS NULL)" }
46+
end
47+
end
1648
end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
object false
2+
3+
child(@preupgrade_report_entries => :results) do
4+
extends "api/v2/preupgrade_report_entries/main"
5+
end
6+
7+
node(:total) { @preupgrade_report_entries.total_entries }
8+
node(:subtotal) { @preupgrade_report_entries.total_entries }
9+
node(:page) { params[:page].to_i > 0 ? params[:page].to_i : 1 }
10+
node(:per_page) { params[:per_page].to_i > 0 ? params[:per_page].to_i : Setting[:entries_per_page] }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extends 'api/v2/preupgrade_report_entries/base'
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
object @preupgrade_report
2+
attributes :id, :status, :reported_at
23

3-
extends 'api/v2/preupgrade_reports/base'
4-
5-
child :preupgrade_report_entries do
6-
extends 'api/v2/preupgrade_report_entries/base'
4+
child(@entries => :results) do
5+
extends "api/v2/preupgrade_report_entries/main"
76
end
7+
8+
node(:total) { @total }
9+
node(:subtotal) { @subtotal }
10+
node(:page) { params[:page].to_i > 0 ? params[:page].to_i : 1 }
11+
node(:per_page) { params[:per_page].to_i > 0 ? params[:per_page].to_i : Setting[:entries_per_page] }

config/routes.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
Rails.application.routes.draw do
44
resources :preupgrade_reports, :only => %i[index]
55

6+
resources :preupgrade_report_entries, only: [] do
7+
collection do
8+
get :auto_complete_search
9+
end
10+
end
11+
612
namespace :api, defaults: { format: 'json' } do
713
scope '(:apiv)', module: :v2, defaults: { apiv: 'v2' }, apiv: /v2/,
814
constraints: ApiConstraints.new( version: 2, default: true) do

test/functional/api/v2/preupgrade_reports_controller_test.rb

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ class PreupgradeReportsControllerTest < ActionController::TestCase
2222
get :show, params: { id: @report.id }
2323
assert_response :success
2424

25-
response = JSON.parse(@response.body)
26-
assert_equal response['id'], @report.id
27-
assert_not_empty response['preupgrade_report_entries']
25+
body = JSON.parse(@response.body)
26+
assert_equal @report.id, body['id']
27+
assert_not_empty body['results']
28+
assert_not_nil body['total']
29+
assert_not_nil body['subtotal']
2830
end
2931

3032
test 'should get :job_invocation' do
@@ -96,7 +98,7 @@ class PreupgradeReportsControllerTest < ActionController::TestCase
9698
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
9799
end
98100

99-
test 'should not get :job_invocation' do
101+
test 'should not get :show' do
100102
get :show, params: { id: @report.id }, session: set_session_user(@user)
101103
assert_response :forbidden
102104
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
@@ -108,6 +110,33 @@ class PreupgradeReportsControllerTest < ActionController::TestCase
108110
assert_includes JSON.parse(@response.body)['error']['missing_permissions'], 'view_hosts'
109111
end
110112
end
113+
114+
test 'should filter entries by search on :show' do
115+
get :show, params: { id: @report.id, search: "title = \"#{@entry.title}\"" }
116+
assert_response :success
117+
body = JSON.parse(@response.body)
118+
assert_equal 1, body['results'].length
119+
assert_equal @entry.id, body['results'].first['id']
120+
end
121+
122+
test 'should sort entries on :show' do
123+
FactoryBot.create(:preupgrade_report_entry, host: @host, preupgrade_report: @report,
124+
title: 'Aaa first alphabetically')
125+
get :show, params: { id: @report.id, order: 'title ASC' }
126+
assert_response :success
127+
titles = JSON.parse(@response.body)['results'].map { |e| e['title'] }
128+
assert_equal titles.sort, titles
129+
end
130+
131+
test ':show always returns paginated results with total and subtotal' do
132+
get :show, params: { id: @report.id }
133+
assert_response :success
134+
body = JSON.parse(@response.body)
135+
assert_not_empty body['results']
136+
assert_not_nil body['total']
137+
assert_not_nil body['subtotal']
138+
assert_equal body['total'], body['subtotal']
139+
end
111140
end
112141
end
113142
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

test/models/preupgrade_report_entry_test.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,23 @@ class PreupgradeReportEntryTest < ActiveSupport::TestCase
3333
assert_equal details.size, 0
3434
end
3535
end
36+
37+
describe 'scoped_search' do
38+
it 'filters correctly by has_remediation and inhibitor' do
39+
host = FactoryBot.create(:host)
40+
report = FactoryBot.create(:preupgrade_report)
41+
42+
entry1 = FactoryBot.create(:preupgrade_report_entry, preupgrade_report: report, host: host,
43+
flags: ['inhibitor'],
44+
detail: { 'remediations' => [{ 'type' => 'hint' }] })
45+
entry2 = FactoryBot.create(:preupgrade_report_entry, preupgrade_report: report, host: host,
46+
flags: [],
47+
detail: nil)
48+
49+
assert_includes PreupgradeReportEntry.search_for('inhibitor = yes'), entry1
50+
assert_not_includes PreupgradeReportEntry.search_for('inhibitor = yes'), entry2
51+
assert_includes PreupgradeReportEntry.search_for('has_remediation = no'), entry2
52+
assert_not_includes PreupgradeReportEntry.search_for('has_remediation = no'), entry1
53+
end
54+
end
3655
end

0 commit comments

Comments
 (0)