superset 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.buildkite/pipeline.yml +16 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +13 -0
  5. data/CHANGELOG.md +48 -0
  6. data/Dockerfile +17 -0
  7. data/LICENSE +21 -0
  8. data/README.md +205 -0
  9. data/Rakefile +12 -0
  10. data/doc/duplicate_dashboards.md +214 -0
  11. data/doc/setting_up_personal_api_credentials.md +127 -0
  12. data/docker-compose.override.yml +10 -0
  13. data/docker-compose.yml +8 -0
  14. data/env.sample +9 -0
  15. data/lib/loggers/duplicate_dashboard_logger.rb +15 -0
  16. data/lib/superset/authenticator.rb +55 -0
  17. data/lib/superset/chart/bulk_delete.rb +40 -0
  18. data/lib/superset/chart/delete.rb +30 -0
  19. data/lib/superset/chart/get.rb +56 -0
  20. data/lib/superset/chart/list.rb +59 -0
  21. data/lib/superset/chart/update_dataset.rb +90 -0
  22. data/lib/superset/client.rb +53 -0
  23. data/lib/superset/credential/api_user.rb +25 -0
  24. data/lib/superset/credential/embedded_user.rb +25 -0
  25. data/lib/superset/dashboard/bulk_delete.rb +42 -0
  26. data/lib/superset/dashboard/bulk_delete_cascade.rb +52 -0
  27. data/lib/superset/dashboard/charts/list.rb +47 -0
  28. data/lib/superset/dashboard/compare.rb +94 -0
  29. data/lib/superset/dashboard/copy.rb +78 -0
  30. data/lib/superset/dashboard/datasets/list.rb +74 -0
  31. data/lib/superset/dashboard/delete.rb +42 -0
  32. data/lib/superset/dashboard/embedded/get.rb +56 -0
  33. data/lib/superset/dashboard/embedded/put.rb +35 -0
  34. data/lib/superset/dashboard/export.rb +98 -0
  35. data/lib/superset/dashboard/get.rb +51 -0
  36. data/lib/superset/dashboard/info.rb +17 -0
  37. data/lib/superset/dashboard/list.rb +99 -0
  38. data/lib/superset/dashboard/put.rb +37 -0
  39. data/lib/superset/dashboard/warm_up_cache.rb +42 -0
  40. data/lib/superset/database/get.rb +30 -0
  41. data/lib/superset/database/get_schemas.rb +25 -0
  42. data/lib/superset/database/list.rb +51 -0
  43. data/lib/superset/dataset/bulk_delete.rb +41 -0
  44. data/lib/superset/dataset/create.rb +62 -0
  45. data/lib/superset/dataset/delete.rb +30 -0
  46. data/lib/superset/dataset/duplicate.rb +62 -0
  47. data/lib/superset/dataset/get.rb +56 -0
  48. data/lib/superset/dataset/list.rb +41 -0
  49. data/lib/superset/dataset/update_query.rb +56 -0
  50. data/lib/superset/dataset/update_schema.rb +120 -0
  51. data/lib/superset/dataset/warm_up_cache.rb +41 -0
  52. data/lib/superset/display.rb +42 -0
  53. data/lib/superset/enumerations/object_type.rb +11 -0
  54. data/lib/superset/file_utilities.rb +19 -0
  55. data/lib/superset/guest_token.rb +69 -0
  56. data/lib/superset/logger.rb +20 -0
  57. data/lib/superset/request.rb +62 -0
  58. data/lib/superset/route_info.rb +34 -0
  59. data/lib/superset/security/permissions_resources/list.rb +22 -0
  60. data/lib/superset/security/role/create.rb +25 -0
  61. data/lib/superset/security/role/get.rb +32 -0
  62. data/lib/superset/security/role/list.rb +45 -0
  63. data/lib/superset/security/role/permission/create.rb +35 -0
  64. data/lib/superset/security/role/permission/get.rb +37 -0
  65. data/lib/superset/security/user/create.rb +49 -0
  66. data/lib/superset/security/user/get.rb +27 -0
  67. data/lib/superset/security/user/list.rb +42 -0
  68. data/lib/superset/services/duplicate_dashboard.rb +298 -0
  69. data/lib/superset/sqllab/execute.rb +52 -0
  70. data/lib/superset/tag/add_to_object.rb +46 -0
  71. data/lib/superset/tag/get.rb +30 -0
  72. data/lib/superset/tag/list.rb +37 -0
  73. data/lib/superset/version.rb +5 -0
  74. data/lib/superset.rb +17 -0
  75. data/log/README.md +4 -0
  76. data/superset.gemspec +55 -0
  77. metadata +300 -0
@@ -0,0 +1,52 @@
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
+ # There are NO CHECKS currently to confirm if a dataset is used on other dashboards.
6
+
7
+ module Superset
8
+ module Dashboard
9
+ class BulkDeleteCascade
10
+ class InvalidParameterError < StandardError; end
11
+
12
+ attr_reader :dashboard_ids
13
+
14
+ def initialize(dashboard_ids: [])
15
+ @dashboard_ids = dashboard_ids
16
+ end
17
+
18
+ def perform
19
+ raise InvalidParameterError, "dashboard_ids array of integers expected" unless dashboard_ids.is_a?(Array)
20
+ raise InvalidParameterError, "dashboard_ids array must contain Integer only values" unless dashboard_ids.all? { |item| item.is_a?(Integer) }
21
+
22
+ dashboard_ids.sort.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
+ true
29
+ end
30
+
31
+ private
32
+
33
+ def delete_datasets(dashboard_id)
34
+ datasets_to_delete = Superset::Dashboard::Datasets::List.new(dashboard_id).datasets_details.map{|d| d[:id] }
35
+ Superset::Dataset::BulkDelete.new(dataset_ids: datasets_to_delete).perform if datasets_to_delete.any?
36
+ end
37
+
38
+ def delete_charts(dashboard_id)
39
+ charts_to_delete = Superset::Dashboard::Charts::List.new(dashboard_id).chart_ids
40
+ Superset::Chart::BulkDelete.new(chart_ids: charts_to_delete).perform if charts_to_delete.any?
41
+ end
42
+
43
+ def delete_dashboard(dashboard_id)
44
+ Superset::Dashboard::Delete.new(dashboard_id: dashboard_id, confirm_zero_charts: true).perform
45
+ end
46
+
47
+ def logger
48
+ @logger ||= Superset::Logger.new
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,47 @@
1
+ module Superset
2
+ module Dashboard
3
+ module Charts
4
+ class List < Superset::Request
5
+ attr_reader :id # dashboard id
6
+
7
+ def self.call(id)
8
+ self.new(id).list
9
+ end
10
+
11
+ def initialize(id)
12
+ @id = id
13
+ end
14
+
15
+ def chart_ids
16
+ result.map { |c| c[:id] }
17
+ end
18
+
19
+ def rows
20
+ result.map do |c|
21
+ [
22
+ c[:id],
23
+ c[:slice_name],
24
+ c[:form_data][:datasource],
25
+ # c[:form_data][:dashboards] # NOTE: form_data dashboards is not accurate .. looks to be bugs related to copying charts
26
+ ]
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def route
33
+ "dashboard/#{id}/charts"
34
+ end
35
+
36
+ def list_attributes
37
+ ['id', 'slice_name', 'datasource'].map(&:to_sym)
38
+ end
39
+
40
+ # when displaying a list of datasets, show dashboard id and title as well
41
+ def title
42
+ @title ||= [id, Superset::Dashboard::Get.new(id).title].join(' ')
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,94 @@
1
+ # A validation checker for comparing dashboards.
2
+ # This class is used to compare two dashboards by their datasets, charts, native filters and cross filters.
3
+ # Output is displayed in a table format to the ruby console
4
+ #
5
+ # Usage: Superset::Dashboard::Compare.new(first_dashboard_id: 322, second_dashboard_id: 347).perform
6
+ #
7
+ module Superset
8
+ module Dashboard
9
+ class Compare
10
+
11
+ attr_reader :first_dashboard_id, :second_dashboard_id
12
+
13
+ def initialize(first_dashboard_id: , second_dashboard_id: )
14
+ @first_dashboard_id = first_dashboard_id
15
+ @second_dashboard_id = second_dashboard_id
16
+ end
17
+
18
+
19
+ def perform
20
+ raise "Error: first_dashboard_id integer is required" unless first_dashboard_id.present? && first_dashboard_id.is_a?(Integer)
21
+ raise "Error: second_dashboard_id integer is required" unless second_dashboard_id.present? && second_dashboard_id.is_a?(Integer)
22
+
23
+ list_datasets
24
+ list_charts
25
+ list_native_filters
26
+ list_cross_filters
27
+
28
+ end
29
+
30
+ def first_dashboard
31
+ @first_dashboard ||= Get.new(first_dashboard_id).result
32
+ end
33
+
34
+ def second_dashboard
35
+ @second_dashboard ||= Get.new(second_dashboard_id).result
36
+ end
37
+
38
+ def list_datasets
39
+ puts "\n ====== DASHBOARD DATASETS ====== "
40
+ Superset::Dashboard::Datasets::List.new(first_dashboard_id).list
41
+ Superset::Dashboard::Datasets::List.new(second_dashboard_id).list
42
+ end
43
+
44
+ def list_charts
45
+ puts "\n ====== DASHBOARD CHARTS ====== "
46
+ Superset::Dashboard::Charts::List.new(first_dashboard_id).list
47
+ puts ''
48
+ Superset::Dashboard::Charts::List.new(second_dashboard_id).list
49
+ end
50
+
51
+ def list_native_filters
52
+ puts "\n ====== DASHBOARD NATIVE FILTERS ====== "
53
+ list_native_filters_for(first_dashboard)
54
+ puts ''
55
+ list_native_filters_for(second_dashboard)
56
+ end
57
+
58
+ def list_cross_filters
59
+ puts "\n ====== DASHBOARD CROSS FILTERS ====== "
60
+ list_cross_filters_for(first_dashboard)
61
+ puts ''
62
+ list_cross_filters_for(second_dashboard)
63
+ end
64
+
65
+ def native_filter_configuration(dashboard_result)
66
+ rows = []
67
+ JSON.parse(dashboard_result['json_metadata'])['native_filter_configuration'].each do |filter|
68
+ filter['targets'].each {|t| rows << [ t['column']['name'], t['datasetId'] ] }
69
+ end
70
+ rows
71
+ end
72
+
73
+ def list_native_filters_for(dashboard_result)
74
+ puts Terminal::Table.new(
75
+ title: [dashboard_result['id'], dashboard_result['dashboard_title']].join(' - '),
76
+ headings: ['Filter Name', 'Dataset Id'],
77
+ rows: native_filter_configuration(dashboard_result)
78
+ )
79
+ end
80
+
81
+ def cross_filter_configuration(dashboard_result)
82
+ JSON.parse(dashboard_result['json_metadata'])['chart_configuration'].map {|k, v| [ v['id'], v['crossFilters'].to_s ] }
83
+ end
84
+
85
+ def list_cross_filters_for(dashboard_result)
86
+ puts Terminal::Table.new(
87
+ title: [dashboard_result['id'], dashboard_result['dashboard_title']].join(' - '),
88
+ headings: ['Chart Id', 'Cross Filter Config'],
89
+ rows: cross_filter_configuration(dashboard_result)
90
+ )
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,78 @@
1
+
2
+ # TODO: some work to happen around TAGS still .. ie 'template' tag would indicate it tested and available to be copied.
3
+ # TODO: also need to ensoure that the embedded details are not duplicated across to the new dashboard
4
+
5
+ module Superset
6
+ module Dashboard
7
+ class Copy < Superset::Request
8
+
9
+ attr_reader :source_dashboard_id, :duplicate_slices, :clear_shared_label_colors
10
+
11
+ def initialize(source_dashboard_id: , duplicate_slices: false, clear_shared_label_colors: false)
12
+ @source_dashboard_id = source_dashboard_id
13
+ @duplicate_slices = duplicate_slices # boolean indicates whether to duplicate charts OR keep the new dashboard pointing to the same charts as the original
14
+ @clear_shared_label_colors = clear_shared_label_colors
15
+ end
16
+
17
+ def perform
18
+ raise "Error: source_dashboard_id integer is required" unless source_dashboard_id.present? && source_dashboard_id.is_a?(Integer)
19
+ raise "Error: duplicate_slices must be a boolean" unless duplicate_slices_is_boolean?
20
+
21
+ adjust_json_metadata
22
+ response
23
+ Superset::Dashboard::Get.new(id).perform # return the full new dashboard object
24
+ end
25
+
26
+ def params
27
+ {
28
+ "css" => "{}",
29
+ "dashboard_title" => "#{source_dashboard.title}",
30
+ "duplicate_slices" => duplicate_slices,
31
+ "json_metadata" => new_dashboard_json_metadata.to_json,
32
+ }
33
+ end
34
+
35
+ def response
36
+ @response ||= client.post(route, params)
37
+ end
38
+
39
+ def id
40
+ response["result"]["id"]
41
+ end
42
+
43
+ private
44
+
45
+ def route
46
+ "dashboard/#{source_dashboard_id}/copy/"
47
+ end
48
+
49
+ def adjust_json_metadata
50
+ # when copying a DB via the API, chart positions need to be nested under json_metadata according to the GUI copy function (as per dev tools investigation in browser)
51
+ new_dashboard_json_metadata.merge!( "positions" => source_dashboard.positions )
52
+
53
+ if clear_shared_label_colors
54
+ # if coping a dashboard to a new db schema .. shared label colors will not be relevant/match as they are specific to the previous schemas dataset values
55
+ new_dashboard_json_metadata.merge!( "shared_label_colors" => {} )
56
+ end
57
+ end
58
+
59
+ def source_dashboard
60
+ @source_dashboard ||= begin
61
+ dash = Get.new(source_dashboard_id)
62
+ dash.response
63
+ dash
64
+ rescue => e
65
+ raise "Error retrieving source dashboard #{e.message}"
66
+ end
67
+ end
68
+
69
+ def new_dashboard_json_metadata
70
+ @new_dashboard_json_metadata ||= source_dashboard.json_metadata
71
+ end
72
+
73
+ def duplicate_slices_is_boolean?
74
+ [true, false].include?(duplicate_slices)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,74 @@
1
+ # 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 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
5
+
6
+ module Superset
7
+ module Dashboard
8
+ module Datasets
9
+ class List < Superset::Request
10
+ attr_reader :id # dashboard id
11
+
12
+ def self.call(id)
13
+ self.new(id).list
14
+ end
15
+
16
+ def initialize(id)
17
+ @id = id
18
+ end
19
+
20
+ def perform
21
+ response
22
+ self
23
+ end
24
+
25
+ def schemas
26
+ @schemas ||= begin
27
+ all_dashboard_schemas = result.map {|d| d[:schema] }.uniq
28
+
29
+ # For the current superset setup we will assume a dashboard datasets will point to EXACTLY one schema, their own.
30
+ # if not .. we need to know about it. Potentially we could override this check if others do not consider it a problem.
31
+ if all_dashboard_schemas.count > 1
32
+ Rollbar.error("SUPERSET DASHBOARD ERROR: Dashboard id #{id} has multiple dataset schema linked: #{all_dashboard_schemas.to_s}")
33
+ end
34
+ all_dashboard_schemas
35
+ end
36
+ end
37
+
38
+ def datasets_details
39
+ result.map do |details|
40
+ details.slice('id', 'datasource_name', 'schema', 'sql').merge('database' => details['database'].slice('id', 'name', 'backend')).with_indifferent_access
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def route
47
+ "dashboard/#{id}/datasets"
48
+ end
49
+
50
+ def list_attributes
51
+ ['id', 'datasource_name', 'database_id', 'database_name', 'database_backend', 'schema'].map(&:to_sym)
52
+ end
53
+
54
+ def rows
55
+ result.map do |d|
56
+ [
57
+ d[:id],
58
+ d[:datasource_name],
59
+ d[:database][:id],
60
+ d[:database][:name],
61
+ d[:database][:backend],
62
+ d[:schema]
63
+ ]
64
+ end
65
+ end
66
+
67
+ # when displaying a list of datasets, show dashboard title as well
68
+ def title
69
+ @title ||= [id, Superset::Dashboard::Get.new(id).title].join(' ')
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Superset
4
+ module Dashboard
5
+ class Delete < Superset::Request
6
+
7
+ attr_reader :dashboard_id, :confirm_zero_charts
8
+
9
+ def initialize(dashboard_id: , confirm_zero_charts: true)
10
+ @dashboard_id = dashboard_id
11
+ @confirm_zero_charts = confirm_zero_charts
12
+ end
13
+
14
+ def perform
15
+ raise InvalidParameterError, "dashboard_id integer is required" unless dashboard_id.present? && dashboard_id.is_a?(Integer)
16
+
17
+ confirm_zero_charts_on_dashboard if confirm_zero_charts
18
+
19
+ logger.info("Attempting to delete dashboard with id: #{dashboard_id}")
20
+ response
21
+ end
22
+
23
+ def response
24
+ @response ||= client.delete(route)
25
+ end
26
+
27
+ private
28
+
29
+ def confirm_zero_charts_on_dashboard
30
+ raise "Error: Dashboard includes #{dashboard_charts.count} charts. Please delete all charts before deleting the dashboard or override and set confirm_zero_charts: false" if dashboard_charts.count.positive?
31
+ end
32
+
33
+ def dashboard_charts
34
+ @dashboard_charts ||= Superset::Dashboard::Charts::List.new(dashboard_id).rows
35
+ end
36
+
37
+ def route
38
+ "dashboard/#{dashboard_id}"
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ module Superset
2
+ module Dashboard
3
+ module Embedded
4
+ class Get < Superset::Request
5
+ attr_reader :id # dashboard id
6
+
7
+ def self.call(id)
8
+ self.new(id).list
9
+ end
10
+
11
+ def initialize(id)
12
+ @id = id
13
+ end
14
+
15
+ def response
16
+ @response ||= client.get(route)
17
+ rescue Happi::Error::NotFound => e
18
+ logger.info("Dashboard #{id} has no Embedded settings. (skipping)") # some dashboards don't have embedded settings, fine to ignore.
19
+ @response = { result: [] }.with_indifferent_access
20
+ @response
21
+ end
22
+
23
+ def result
24
+ response[:result].empty? ? [] : [ super ] # wrap single result in an array so it can be used in the tt list and table
25
+ end
26
+
27
+ def allowed_domains
28
+ result.first['allowed_domains'] unless response[:result].empty?
29
+ end
30
+
31
+ def uuid
32
+ result.first['uuid'] unless response[:result].empty?
33
+ end
34
+
35
+ def list
36
+ super unless response[:result].empty?
37
+ end
38
+
39
+ private
40
+
41
+ def route
42
+ "dashboard/#{id}/embedded"
43
+ end
44
+
45
+ def list_attributes
46
+ [:dashboard_id, :uuid, :allowed_domains, :changed_on]
47
+ end
48
+
49
+ # when displaying embedded details, show dashboard title as well
50
+ def title
51
+ Superset::Dashboard::Get.new(id).title
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,35 @@
1
+ module Superset
2
+ module Dashboard
3
+ module Embedded
4
+ class Put < Superset::Request
5
+ attr_reader :dashboard_id, :allowed_domains
6
+
7
+ def initialize(dashboard_id: , allowed_domains: )
8
+ @dashboard_id = dashboard_id
9
+ @allowed_domains = allowed_domains
10
+ end
11
+
12
+ def response
13
+ raise InvalidParameterError, 'dashboard_id integer is required' if dashboard_id.nil? || dashboard_id.class != Integer
14
+ raise InvalidParameterError, 'allowed_domains array is required' if allowed_domains.nil? || allowed_domains.class != Array
15
+
16
+ @response ||= client.put(route, params)
17
+ end
18
+
19
+ def params
20
+ { "allowed_domains": allowed_domains }
21
+ end
22
+
23
+ def uuid
24
+ result['uuid'] unless response[:result].empty?
25
+ end
26
+
27
+ private
28
+
29
+ def route
30
+ "dashboard/#{dashboard_id}/embedded"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,98 @@
1
+ # Will export the zip file to /tmp/superset_dashboards with zip filename adjusted to include the dashboard_id
2
+ # Example zipfile: dashboard_#{dashboard_id}_export_#{datestamp}.zip
3
+ # Will then unzip and copy the files into the destination_path with the dashboard_id as a subfolder
4
+ #
5
+ # Usage
6
+ # Superset::Dashboard::Export.new(dashboard_id: 15, destination_path: '/tmp/superset_dashboard_backups/').perform
7
+ #
8
+
9
+ require 'superset/file_utilities'
10
+
11
+ module Superset
12
+ module Dashboard
13
+ class Export < Request
14
+ include FileUtilities
15
+
16
+ TMP_SUPERSET_DASHBOARD_PATH = '/tmp/superset_dashboards'
17
+
18
+ attr_reader :dashboard_id, :destination_path
19
+
20
+ def initialize(dashboard_id: , destination_path: )
21
+ @dashboard_id = dashboard_id
22
+ @destination_path = destination_path.chomp('/')
23
+ end
24
+
25
+ def perform
26
+ create_tmp_dir
27
+ save_exported_zip_file
28
+ unzip_files
29
+ copy_export_files_to_destination_path if destination_path
30
+ end
31
+
32
+ def response
33
+ @response ||= client.call(
34
+ :get,
35
+ client.url(route),
36
+ client.param_check(params)
37
+ )
38
+ end
39
+
40
+ private
41
+
42
+ def params
43
+ { "q": "!(#{dashboard_id})" } # pulled off chrome dev tools doing a GUI export. Swagger interface not helpfull with this endpoint.
44
+ end
45
+
46
+ def save_exported_zip_file
47
+ File.open(zip_file_name, 'wb') { |fp| fp.write(response.body) }
48
+ end
49
+
50
+ def unzip_files
51
+ @extracted_files = unzip_file(zip_file_name, tmp_uniq_dashboard_path)
52
+ end
53
+
54
+ def download_folder
55
+ File.dirname(extracted_files[0])
56
+ end
57
+
58
+ def copy_export_files_to_destination_path
59
+ path_with_dash_id = File.join(destination_path, dashboard_id.to_s)
60
+ FileUtils.mkdir_p(path_with_dash_id) unless File.directory?(path_with_dash_id)
61
+
62
+ Dir.glob("#{download_folder}/*").each do |item|
63
+ FileUtils.cp_r(item, path_with_dash_id)
64
+ end
65
+ end
66
+
67
+ def zip_file_name
68
+ @zip_file_name ||= "#{tmp_uniq_dashboard_path}/dashboard_#{dashboard_id}_export_#{datestamp}.zip"
69
+ end
70
+
71
+ def create_tmp_dir
72
+ FileUtils.mkdir_p(tmp_uniq_dashboard_path) unless File.directory?(tmp_uniq_dashboard_path)
73
+ end
74
+
75
+ # uniq random tmp folder name for each export
76
+ # this will allow us to do a wildcard glop on the folder to get the files
77
+ def tmp_uniq_dashboard_path
78
+ @tmp_uniq_dashboard_path ||= File.join(TMP_SUPERSET_DASHBOARD_PATH, uuid)
79
+ end
80
+
81
+ def uuid
82
+ SecureRandom.uuid
83
+ end
84
+
85
+ def extracted_files
86
+ @extracted_files ||= []
87
+ end
88
+
89
+ def route
90
+ "dashboard/export/"
91
+ end
92
+
93
+ def datestamp
94
+ @datestamp ||= Time.now.strftime('%Y%m%d')
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,51 @@
1
+ module Superset
2
+ module Dashboard
3
+ class Get < Superset::Request
4
+
5
+ attr_reader :id
6
+
7
+ def initialize(id)
8
+ @id = id
9
+ end
10
+
11
+ def self.call(id)
12
+ self.new(id).list
13
+ end
14
+
15
+ def perform
16
+ response
17
+ self
18
+ end
19
+
20
+ def title
21
+ "#{result['dashboard_title']}"
22
+ end
23
+
24
+ def json_metadata
25
+ JSON.parse(result['json_metadata'])
26
+ end
27
+
28
+ def positions
29
+ JSON.parse(result['position_json'])
30
+ end
31
+
32
+ def url
33
+ "#{superset_host}#{result['url']}"
34
+ end
35
+
36
+ private
37
+
38
+ def route
39
+ "dashboard/#{id}"
40
+ end
41
+
42
+ def rows
43
+ result['charts'].map {|c| [c]}
44
+ end
45
+
46
+ def headings
47
+ ['Charts']
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,17 @@
1
+ module Superset
2
+ module Dashboard
3
+ class Info < Superset::Request
4
+ alias result response
5
+
6
+ def filters
7
+ result['filters']
8
+ end
9
+
10
+ private
11
+
12
+ def route
13
+ "dashboard/_info"
14
+ end
15
+ end
16
+ end
17
+ end