Skip to content

Commit 539cac6

Browse files
committed
NEP-16354 add delete cascade endpoint
1 parent 3247a47 commit 539cac6

File tree

6 files changed

+108
-22
lines changed

6 files changed

+108
-22
lines changed

lib/superset/dashboard/bulk_delete.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# 2 or do not have any charts or filters linked to them
77
# ( not sure if this needed at this point )
88

9+
# NOTE: deletes the Dashboard Only. Use Dashboard::BulkDeleteCascade to delete all related objects
910
module Superset
1011
module Dashboard
1112
class BulkDelete < Superset::Request
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+
# WARNING: DESTRUCTIVE OPERATION .. use with caution
4+
# This class is used to delete multiple dashboards and all related charts and datasets.
5+
6+
module Superset
7+
module Dashboard
8+
class BulkDeleteCascade
9+
class InvalidParameterError < StandardError; end
10+
11+
attr_reader :dashboard_ids
12+
13+
def initialize(dashboard_ids: [])
14+
@dashboard_ids = dashboard_ids.sort # delete sequentially
15+
end
16+
17+
def perform
18+
raise InvalidParameterError, "dashboard_ids array of integers expected" unless dashboard_ids.is_a?(Array)
19+
raise InvalidParameterError, "dashboard_ids array must contain Integer only values" unless dashboard_ids.all? { |item| item.is_a?(Integer) }
20+
# TODO check if dashboard_ids are valid
21+
22+
dashboard_ids.each do |dashboard_id|
23+
logger.info("Dashboard Id: #{dashboard_id.to_s} Attempting CASCADE delete of dashboard, charts, datasets")
24+
delete_datasets(dashboard_id)
25+
delete_charts(dashboard_id)
26+
delete_dashboard(dashboard_id)
27+
end
28+
end
29+
30+
private
31+
32+
def delete_datasets(dashboard_id)
33+
datasets_to_delete = Superset::Dashboard::Datasets::List.new(dashboard_id).datasets_details.map{|d| d[:id] }
34+
Superset::Dataset::BulkDelete.new(dataset_ids: datasets_to_delete).perform if datasets_to_delete.any?
35+
end
36+
37+
def delete_charts(dashboard_id)
38+
charts_to_delete = Superset::Dashboard::Charts::List.new(dashboard_id).chart_ids
39+
Superset::Chart::BulkDelete.new(chart_ids: charts_to_delete).perform if charts_to_delete.any?
40+
end
41+
42+
def delete_dashboard(dashboard_id)
43+
Superset::Dashboard::Delete.new(dashboard_id: dashboard_id, confirm_zero_charts: true).perform
44+
end
45+
46+
def logger
47+
@logger ||= Superset::Logger.new
48+
end
49+
end
50+
end
51+
end

lib/superset/dashboard/put.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ def perform
1717
raise "Error: params hash is required" unless params.present? && params.is_a?(Hash)
1818

1919
response
20-
Superset::Dashboard::Get.new(id).perform
2120
end
2221

2322
def response

lib/superset/services/duplicate_dashboard.rb

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ module Superset
77
module Services
88
class DuplicateDashboard < Superset::Request
99

10-
attr_reader :source_dashboard_id, :target_schema, :target_database_id, :allowed_domains, :tags
10+
attr_reader :source_dashboard_id, :target_schema, :target_database_id, :allowed_domains, :tags, :publish
1111

12-
def initialize(source_dashboard_id:, target_schema:, target_database_id: , allowed_domains: [], tags: [])
12+
def initialize(source_dashboard_id:, target_schema:, target_database_id: , allowed_domains: [], tags: [], publish: false)
1313
@source_dashboard_id = source_dashboard_id
1414
@target_schema = target_schema
1515
@target_database_id = target_database_id
1616
@allowed_domains = allowed_domains
1717
@tags = tags
18+
@publish = publish
1819
end
1920

2021
def perform
@@ -43,10 +44,12 @@ def perform
4344

4445
add_tags_to_new_dashboard
4546

47+
publish_dashboard if publish
48+
4649
end_log_message
4750

4851
# return the new dashboard id and url
49-
{ new_dashboard_id: new_dashboard.id, new_dashboard_url: new_dashboard.url }
52+
{ new_dashboard_id: new_dashboard.id, new_dashboard_url: new_dashboard.url, published: publish }
5053

5154
rescue => e
5255
logger.error("#{e.message}")
@@ -153,6 +156,10 @@ def update_source_dashboard_json_metadata
153156
Superset::Dashboard::Put.new(target_dashboard_id: new_dashboard.id, params: { "json_metadata" => @new_dashboard_json_metadata_configuration.to_json }).perform
154157
end
155158

159+
def publish_dashboard
160+
Superset::Dashboard::Put.new(target_dashboard_id: new_dashboard.id, params: { published: publish } ).perform
161+
end
162+
156163
def new_dashboard
157164
@new_dashboard ||= begin
158165
copy = Superset::Dashboard::Copy.new(

spec/superset/dashboard/put_spec.rb

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,16 @@
99
"positions" => { "key2" => "value2" }
1010
}.to_json
1111
}}
12-
13-
let(:new_dashboard_id) { 2 }
14-
let(:new_dashboard_instance) { instance_double("Superset::Dashboard::Get") }
12+
let(:response) { { "result" => { "id" => 2, "last_modified_time" => 1708484547.0 } } }
1513

1614
before do
17-
allow(subject).to receive(:response).and_return( { "result" =>
18-
{"id"=>new_dashboard_id, "last_modified_time"=>1708484547.0} }
19-
)
15+
allow(subject).to receive(:response).and_return(response)
2016
end
2117

2218
describe 'perform' do
2319
context 'with valid params' do
24-
before do
25-
allow(Superset::Dashboard::Get).to receive(:new).with(new_dashboard_id).and_return(new_dashboard_instance)
26-
allow(new_dashboard_instance).to receive(:perform).and_return(new_dashboard_instance)
27-
end
28-
29-
it 'returns the new dashboard object' do
30-
expect(subject.perform).to be new_dashboard_instance
20+
it 'returns response' do
21+
expect(subject.perform).to eq(response)
3122
end
3223
end
3324

spec/superset/services/duplicate_dashboard_spec.rb

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
context 'completes duplicate process' do
134134
context 'and returns the new dashboard details' do
135135
specify do
136-
expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2" })
136+
expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2", published: false})
137137
end
138138
end
139139

@@ -187,7 +187,7 @@
187187
expect(Superset::Dashboard::Embedded::Put).to_not receive(:new)
188188
end
189189

190-
specify { expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2" }) }
190+
specify { expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2", published: false}) }
191191
end
192192

193193
context 'are not empty' do
@@ -197,13 +197,13 @@
197197
expect(Superset::Dashboard::Embedded::Put).to receive(:new).with(dashboard_id: new_dashboard_id, allowed_domains: allowed_domains).and_return(double(result: { allowed_domains: allowed_domains }))
198198
end
199199

200-
specify { expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2" }) }
200+
specify { expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2", published: false}) }
201201
end
202202
end
203203

204204
context 'and tags' do
205205
context 'are empty' do
206-
specify { expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2" }) }
206+
specify { expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2", published: false}) }
207207
end
208208

209209
context 'are not empty' do
@@ -213,10 +213,47 @@
213213
expect(Superset::Tag::AddToObject).to receive(:new).with(object_type_id: ObjectType::DASHBOARD, object_id: new_dashboard_id, tags: tags).and_return(double(perform: true))
214214
end
215215

216-
specify { expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2" }) }
216+
specify { expect(subject.perform).to eq( { new_dashboard_id: 2, new_dashboard_url: "http://superset-host.com/superset/dashboard/2", published: false}) }
217217
end
218218
end
219219

220+
context 'and publish attr is' do
221+
context 'excluded from params' do
222+
before do
223+
expect(Superset::Dashboard::Put).to_not receive(:new).with(
224+
target_dashboard_id: new_dashboard_id,
225+
params: { published: false })
226+
end
227+
228+
specify 'defaults to false' do
229+
expect(subject.perform).to eq( {
230+
new_dashboard_id: 2,
231+
new_dashboard_url: "http://superset-host.com/superset/dashboard/2",
232+
published: false
233+
})
234+
end
235+
end
236+
237+
context 'included in params as true' do
238+
subject { described_class.new(
239+
source_dashboard_id: source_dashboard_id,
240+
target_schema: target_schema,
241+
target_database_id: target_database_id,
242+
publish: true ) }
243+
244+
before do
245+
expect(Superset::Dashboard::Put).to receive(:new).with(
246+
target_dashboard_id: new_dashboard_id,
247+
params: { published: true }).and_return(double(perform: true))
248+
end
249+
250+
specify { expect(subject.perform).to eq( {
251+
new_dashboard_id: 2,
252+
new_dashboard_url: "http://superset-host.com/superset/dashboard/2",
253+
published: true
254+
}) }
255+
end
256+
end
220257
end
221258

222259
context 'with invalid params' do

0 commit comments

Comments
 (0)