diff --git a/app/controllers/api/widget_sets_controller.rb b/app/controllers/api/widget_sets_controller.rb new file mode 100644 index 0000000000..4a42108728 --- /dev/null +++ b/app/controllers/api/widget_sets_controller.rb @@ -0,0 +1,58 @@ +module Api + class WidgetSetsController < BaseController + REQUIRED_FIELDS_TO_COPY = %w[name].freeze + ALLOWED_FIELDS = REQUIRED_FIELDS_TO_COPY + %w[group description guid read_only set_data].freeze + SET_DATA_COLS = %i[col1 col2 col3].freeze + + def create_resource(type, id = nil, data = nil) + raise_if_unsupported_fields_passed(data) + + data['group_id'] = parse_resource_from(data.delete('group')) + data['owner_id'] = data['group_id'] + super(type, id, data) + end + + def edit_resource(type, id = nil, data = nil) + raise_if_unsupported_fields_passed(data, ALLOWED_FIELDS - %w[name group]) + + super(type, id, data) + end + + def delete_resource(type, id = nil, data = nil) + klass = collection_class(type) + widget_set = resource_search(id, type, klass) + raise ArgumentError, "Unable to delete read_only widget_set" if widget_set.read_only? + + api_action(type, id) do |_klass| + super(type, id, data) + + action_result(true, "Dashboard #{widget_set.name} has been successfully deleted.") + end + end + + def copy_resource(type, id = nil, data = nil) + raise_if_unsupported_fields_passed(data) + + klass = collection_class(type) + widget_set = resource_search(id, type, klass) + group_id = data['id']&.to_i || parse_resource_from(data['group']) || widget_set.group_id + + widget_set = MiqWidgetSet.copy_dashboard(widget_set, data['name'], data['description'], group_id) + + result = action_result(true, "Dashboard #{data['name']} successfully created.") + add_href_to_result(result, type, widget_set.id) + result + end + + def parse_resource_from(attributes) + return unless attributes + + attributes['id']&.to_i || (attributes['href'] && Api::Href.new(attributes['href']).subject_id) if attributes + end + + def raise_if_unsupported_fields_passed(data, allowed_fields = ALLOWED_FIELDS) + unsupported_fields = data.keys - allowed_fields + raise ArgumentError, "Field(s) #{unsupported_fields.join(", ")} are not supported" if unsupported_fields.present? + end + end +end diff --git a/config/api.yml b/config/api.yml index e5e7af2e60..06053a247d 100644 --- a/config/api.yml +++ b/config/api.yml @@ -4619,6 +4619,51 @@ :identifier: - vm_snapshot_delete - sui_vm_snapshot_delete + :widget_sets: + :description: Dashboards + :identifier: miq_report_dashboard_editor + :options: + - :collection + :verbs: *gpppd + :klass: MiqWidgetSet + :collection_actions: + :get: + - :name: read + :identifier: miq_report_dashboard_editor + :post: + - :name: query + :identifier: miq_report_dashboard_editor + - :name: create + :identifier: db_new + - :name: edit + :identifier: db_edit + - :name: delete + :identifier: db_delete + - :name: copy + :identifier: db_copy + :delete: + - :name: delete + :identifier: db_delete + :resource_actions: + :get: + - :name: read + :identifier: miq_report_dashboard_editor + :post: + - :name: edit + :identifier: db_edit + - :name: delete + :identifier: db_delete + - :name: copy + :identifier: db_copy + :patch: + - :name: edit + :identifier: db_edit + :put: + - :name: edit + :identifier: db_edit + :delete: + - :name: delete + :identifier: db_delete :widgets: :description: Miq Widgets :identifier: miq_report_widget_admin diff --git a/spec/requests/widget_sets_spec.rb b/spec/requests/widget_sets_spec.rb new file mode 100644 index 0000000000..889c473a26 --- /dev/null +++ b/spec/requests/widget_sets_spec.rb @@ -0,0 +1,146 @@ +describe "Widget Sets API" do + let(:group) { User.current_user.current_group } + let(:miq_widget_set) { FactoryBot.create(:miq_widget_set, :owner => group) } + let(:miq_widget_set_other) { FactoryBot.create(:miq_widget_set, :owner => group) } + let(:widgets) { FactoryBot.create_list(:miq_widget, 3) } + let(:widget_params) do + { + "name" => "XXX", + "description" => "YYY", + "set_data" => {"col1" => widgets.map(&:id), + "reset_upon_login" => false, + "locked" => false} + } + end + + before do + User.current_user = User.first + end + + context "GET" do + it "returns single" do + api_basic_authorize collection_action_identifier(:widget_sets, :read, :get) + + get(api_widget_set_url(nil, miq_widget_set)) + + expect(response).to have_http_status(:ok) + expect(response.parsed_body['id'].to_i).to eq(miq_widget_set.id) + end + + it "returns all widget sets" do + api_basic_authorize collection_action_identifier(:widget_sets, :read, :get) + + get(api_widget_sets_url) + + expect(response).to have_http_status(:ok) + widget_sets_hrefs = response.parsed_body['resources'].map { |x| x['href'] } + all_widget_sets_hrefs = MiqWidgetSet.all.map { |ws| api_widget_set_url(nil, ws) } + expect(widget_sets_hrefs).to match_array(all_widget_sets_hrefs) + end + + it "doesn't find widget set" do + api_basic_authorize collection_action_identifier(:widget_sets, :read, :get) + + get(api_widget_set_url(nil, 999_999)) + + expect(response).to have_http_status(:not_found) + end + + it "forbids action get for non-super-admin user" do + expect_forbidden_request do + get(api_widget_set_url(nil, miq_widget_set)) + end + end + end + + context "POST" do + let(:group_href) { api_group_url(nil, group) } + + it "creates widget set" do + api_basic_authorize collection_action_identifier(:widget_sets, :create, :post) + + post api_widget_sets_url, :params => gen_request(:create, widget_params.merge('group' => {'href' => group_href})) + + expect(response).to have_http_status(:ok) + + widget_params["set_data"]["col2"] = [] + widget_params["set_data"]["col3"] = [] + expect(response.parsed_body['results'][0].values_at(*widget_params.keys)).to match_array(widget_params.values) + ws = MiqWidgetSet.find(response.parsed_body['results'][0]['id']) + expect(ws.members.map(&:id)).to eq(widgets.map(&:id)) + group.reload + expect(group.settings["dashboard_order"]).to eq([ws.id]) + end + + it "updates widget set" do + api_basic_authorize collection_action_identifier(:widget_sets, :edit, :post) + + widget_params_for_update = widget_params.except('name') + post api_widget_set_url(nil, miq_widget_set), :params => gen_request(:edit, widget_params_for_update) + + expect(response).to have_http_status(:ok) + expect(response.parsed_body['id'].to_i).to eq(miq_widget_set.id) + widget_params["set_data"]["col2"] = [] + widget_params["set_data"]["col3"] = [] + expect(response.parsed_body.values_at(*widget_params_for_update.keys)).to match_array(widget_params_for_update.values) + ws = MiqWidgetSet.find(response.parsed_body['id']) + expect(ws.members.map(&:id)).to eq(widgets.map(&:id)) + end + + it "deletes widget set" do + api_basic_authorize collection_action_identifier(:widget_sets, :delete, :post) + widget_set_id = miq_widget_set.id + group.settings = {"dashboard_order" => [1, widget_set_id]} + group.save + post api_widget_set_url(nil, miq_widget_set), :params => gen_request(:delete, widget_params) + expect(response).to have_http_status(:ok) + expect(MiqWidgetSet.find_by(:id => widget_set_id)).to be_nil + group.reload + expect(group.settings["dashboard_order"]).not_to include(widget_set_id) + end + + it "forbids action for non-super-admin user" do + expect_forbidden_request do + post(api_widget_sets_url) + end + end + end + + context "PUT" do + it "updates widget set" do + api_basic_authorize collection_action_identifier(:widget_sets, :edit, :post) + params_for_put = widget_params.except('name') + put api_widget_set_url(nil, miq_widget_set), :params => params_for_put + + expect(response).to have_http_status(:ok) + expect(response.parsed_body['id'].to_i).to eq(miq_widget_set.id) + + widget_params["set_data"]["col2"] = [] + widget_params["set_data"]["col3"] = [] + expect(response.parsed_body.values_at(*params_for_put.keys)).to match_array(params_for_put.values) + end + + it "forbids action for non-super-admin user" do + expect_forbidden_request do + put(api_widget_set_url(nil, miq_widget_set)) + end + end + end + + context "DELETE" do + it "deletes widget set" do + api_basic_authorize collection_action_identifier(:widget_sets, :delete, :post) + widget_set_id = miq_widget_set.id + + delete api_widget_set_url(nil, miq_widget_set) + expect(response).to have_http_status(:no_content) + expect(MiqWidgetSet.find_by(:id => widget_set_id)).to be_nil + end + + it "forbids action for non-super-admin user" do + expect_forbidden_request do + delete(api_widget_set_url(nil, miq_widget_set)) + end + end + end +end