Skip to content

Commit 938fbc6

Browse files
authored
Merge pull request #27 from rdytech/NEP-18011-adjust-duplicate-dashboard-filter-validations
NEP-18011-adjust-duplicate-dashboard-filter-validations
2 parents eb7156b + 338ca81 commit 938fbc6

File tree

3 files changed

+61
-18
lines changed

3 files changed

+61
-18
lines changed

lib/superset/dashboard/datasets/list.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# WARNING: Does not take into account datasets with queries that have embedded schema references.
2-
# ie " select * from schema1.table join schema2.table" for a dataset query will not only return the config schema setting not the sql schema reference.
2+
# ie " select * from schema1.table join schema2.table" for a dataset query will ONLY return the datasets config schema setting not the sql query schema references which refers to 2 distinct schemas.
3+
#
4+
# WARNING: Does not return Filter Datasets for the dashboard
35

46
module Superset
57
module Dashboard

lib/superset/services/duplicate_dashboard.rb

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
# Assumptions
1+
# Data Sovereignty validations are enforced, ie confirming
2+
# - all charts datasets on the source dashboard are pointing to the same database schema
3+
# - all filter datasets on the source dashboard are pointing to the same database schema as the charts
4+
25
# - The source dashboard is in the same Superset instance as the target database and target schema
3-
# - All charts datasets on the source dashboard are pointing to the same database schema
46

57

68
module Superset
@@ -195,7 +197,7 @@ def validate_params
195197
# schema validations
196198
raise ValidationError, "Schema #{target_schema} does not exist in target database: #{target_database_id}" unless target_database_available_schemas.include?(target_schema)
197199
raise ValidationError, "The source dashboard datasets are required to point to one schema only. Actual schema list is #{source_dashboard_schemas.join(',')}" if source_dashboard_has_more_than_one_schema?
198-
raise ValidationError, "One or more source dashboard filters point to a different dataset than the dashboard charts. Identified Unpermittied Filter Dataset Ids are #{unpermitted_filter_dataset_ids.to_s}" if unpermitted_filter_dataset_ids.any?
200+
raise ValidationError, "One or more source dashboard filters point to a different schema than the dashboard charts. Identified Unpermittied Filter Dataset Ids are #{unpermitted_filter_dataset_ids.to_s}" if unpermitted_filter_dataset_ids.any?
199201

200202
# new dataset validations
201203
raise ValidationError, "DATASET NAME CONFLICT: The Target Schema #{target_schema} already has existing datasets named: #{target_schema_matching_dataset_names.join(',')}" unless target_schema_matching_dataset_names.empty?
@@ -225,6 +227,7 @@ def source_dashboard_has_more_than_one_schema?
225227
source_dashboard_schemas.count > 1
226228
end
227229

230+
# Data Sovereignty rules expect only 1 value here, and raise a validation error if there is > 1
228231
def source_dashboard_schemas
229232
source_dashboard_datasets.map { |dataset| dataset[:schema] }.uniq
230233
end
@@ -259,10 +262,20 @@ def source_dashboard_filter_dataset_ids
259262
filters_configuration.map { |c| c['targets'] }.flatten.compact.map { |c| c['datasetId'] }.flatten.compact
260263
end
261264

262-
# identify any filters dataset that is not part of the dashboard charts datasets
263-
# unpermitted meaning we only allow filters to be sourced from the dashboard datasets
265+
# Primary Assumption is that all charts datasets on the source dashboard are pointing to the same database schema
266+
# An unpermitted filter will have a dataset that is pulling data from a datasource that is
267+
# different to the dashboard charts database schema
264268
def unpermitted_filter_dataset_ids
265-
source_dashboard_filter_dataset_ids - source_dashboard_dataset_ids
269+
@unpermitted_filter_dataset_ids ||= begin
270+
filter_datasets_not_used_in_charts = source_dashboard_filter_dataset_ids - source_dashboard_dataset_ids
271+
272+
# retrieve any filter_datasets_not_used_in_charts that do not match the source_dashboard_schema
273+
filter_datasets_not_used_in_charts.map do |filter_dataset|
274+
filter_dataset_schema = Superset::Dataset::Get.new(filter_dataset).schema
275+
# return any filter datasets not used in charts that are from a different schema
276+
{ filter_dataset_id: filter_dataset, filter_schema: filter_dataset_schema } if [filter_dataset_schema] != source_dashboard_schemas
277+
end.compact
278+
end
266279
end
267280

268281
def logger

spec/superset/services/duplicate_dashboard_spec.rb

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
let(:existing_target_datasets_list) {[]}
4949

5050
# initial json metadata settings will be copied to the new dashboard and requires updating
51-
let(:json_metadata_initial_settings) do
51+
let(:json_metadata_initial_settings) do
5252
{
5353
"chart_configuration"=>
5454
{ "#{source_chart_1}"=>{"id"=>source_chart_1, "crossFilters"=>{"scope"=>"global", "chartsInScope"=>[source_chart_2]}},
@@ -70,7 +70,7 @@
7070
end
7171

7272
# expected json metadata settings after the new dashboard is created and json is updated
73-
let(:json_metadata_updated_settings) do
73+
let(:json_metadata_updated_settings) do
7474
{
7575
"chart_configuration"=>
7676
{ "#{new_chart_1}"=>{"id"=>new_chart_1, "crossFilters"=>{"scope"=>"global", "chartsInScope"=>[new_chart_2]}},
@@ -141,15 +141,15 @@
141141
context 'with stardard json metadata ids' do
142142
specify do
143143
expect(subject.new_dashboard_json_metadata_configuration).to eq(json_metadata_initial_settings)
144-
subject.perform
144+
subject.perform
145145
expect(subject.new_dashboard_json_metadata_configuration).to eq(json_metadata_updated_settings)
146146
end
147147
end
148148

149149
context 'with non stardard json metadata ids to confirm gsub' do
150150
let(:source_chart_1) { 11 }
151151
let(:source_chart_2) { 1111 }
152-
let(:json_metadata_initial_settings) do
152+
let(:json_metadata_initial_settings) do
153153
{
154154
"chart_configuration"=>
155155
{ "#{source_chart_1}"=>{"id"=>source_chart_1, "crossFilters"=>{"scope"=>"global", "chartsInScope"=>[source_chart_2]}} ,
@@ -161,7 +161,7 @@
161161

162162
let(:new_chart_1) { 222 }
163163
let(:new_chart_2) { 22222 }
164-
let!(:json_metadata_updated_settings) do
164+
let!(:json_metadata_updated_settings) do
165165
{
166166
"chart_configuration"=>
167167
{ "#{new_chart_1}"=>{"id"=>new_chart_1, "crossFilters"=>{"scope"=>"global", "chartsInScope"=>[new_chart_2]}} ,
@@ -173,12 +173,11 @@
173173

174174
specify do
175175
expect(subject.new_dashboard_json_metadata_configuration).to eq(json_metadata_initial_settings)
176-
subject.perform
176+
subject.perform
177177
expect(subject.new_dashboard_json_metadata_configuration).to eq(json_metadata_updated_settings)
178178
end
179179
end
180180
end
181-
182181
end
183182

184183
context 'and embedded domains' do
@@ -289,12 +288,41 @@
289288
end
290289
end
291290

292-
context 'filters set is outside source schema' do
291+
context 'one filters dataset schema not matching the source dashboards schema' do
293292
let(:target_schema) { 'schema_two' }
294-
let(:source_dashboard_filter_dataset_ids) { [101, 202] }
293+
let(:invalid_filter_dataset_id) { 404 }
294+
let(:invalid_filter_dataset_schema) { 'schema_four' }
295+
let(:source_dashboard_filter_dataset_ids) { [101, invalid_filter_dataset_id] }
295296

296297
specify do
297-
expect { subject.perform }.to raise_error(Superset::Request::ValidationError, "One or more source dashboard filters point to a different dataset than the dashboard charts. Identified Unpermittied Filter Dataset Ids are [202]")
298+
# additional filter checks for validations on unpermitted_filter_dataset_ids
299+
expect(Superset::Dataset::Get).to receive(:new).with(invalid_filter_dataset_id).and_return(double(schema: invalid_filter_dataset_schema))
300+
301+
expect { subject.perform }.to raise_error(Superset::Request::ValidationError,
302+
"One or more source dashboard filters point to a different schema than the dashboard charts. " \
303+
"Identified Unpermittied Filter Dataset Ids are " \
304+
"[{:filter_dataset_id=>#{invalid_filter_dataset_id}, :filter_schema=>\"#{invalid_filter_dataset_schema}\"}]")
305+
end
306+
end
307+
308+
context 'more than one filters dataset schema not matching the source dashboards schema' do
309+
let(:target_schema) { 'schema_two' }
310+
let(:invalid_filter_dataset_id) { 404 }
311+
let(:invalid_filter_dataset_schema) { 'schema_four' }
312+
let(:invalid_filter_dataset_id_2) { 505 }
313+
let(:invalid_filter_dataset_schema_2) { 'schema_five' }
314+
let(:source_dashboard_filter_dataset_ids) { [101, invalid_filter_dataset_id, invalid_filter_dataset_id_2] }
315+
316+
specify do
317+
# additional filter checks for validations on unpermitted_filter_dataset_ids
318+
expect(Superset::Dataset::Get).to receive(:new).with(invalid_filter_dataset_id).and_return(double(schema: invalid_filter_dataset_schema))
319+
expect(Superset::Dataset::Get).to receive(:new).with(invalid_filter_dataset_id_2).and_return(double(schema: invalid_filter_dataset_schema_2))
320+
321+
expect { subject.perform }.to raise_error(Superset::Request::ValidationError,
322+
"One or more source dashboard filters point to a different schema than the dashboard charts. " \
323+
"Identified Unpermittied Filter Dataset Ids are " \
324+
"[{:filter_dataset_id=>#{invalid_filter_dataset_id}, :filter_schema=>\"#{invalid_filter_dataset_schema}\"}, " \
325+
"{:filter_dataset_id=>#{invalid_filter_dataset_id_2}, :filter_schema=>\"#{invalid_filter_dataset_schema_2}\"}]")
298326
end
299327
end
300328

@@ -311,7 +339,7 @@
311339
context 'target schema already has matching dataset names' do
312340
let(:existing_target_datasets_list) {[ 'Dataset 1 (COPY)', 'Dataset 2 (COPY)' ]}
313341
specify do
314-
expect { subject.perform }.to raise_error(Superset::Request::ValidationError,
342+
expect { subject.perform }.to raise_error(Superset::Request::ValidationError,
315343
"DATASET NAME CONFLICT: The Target Schema schema_two already has existing datasets named: Dataset 1 (COPY),Dataset 2 (COPY)")
316344
end
317345
end

0 commit comments

Comments
 (0)