gazer 0.2.9

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 (128) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +5 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +35 -0
  8. data/Gemfile.lock +150 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +527 -0
  11. data/Rakefile +27 -0
  12. data/bin/console +35 -0
  13. data/bin/setup +30 -0
  14. data/exe/gzr +40 -0
  15. data/gzr.gemspec +67 -0
  16. data/lib/gzr.rb +25 -0
  17. data/lib/gzr/cli.rb +86 -0
  18. data/lib/gzr/command.rb +251 -0
  19. data/lib/gzr/commands/.gitkeep +1 -0
  20. data/lib/gzr/commands/connection.rb +69 -0
  21. data/lib/gzr/commands/connection/dialects.rb +72 -0
  22. data/lib/gzr/commands/connection/ls.rb +72 -0
  23. data/lib/gzr/commands/dashboard.rb +75 -0
  24. data/lib/gzr/commands/dashboard/cat.rb +67 -0
  25. data/lib/gzr/commands/dashboard/import.rb +256 -0
  26. data/lib/gzr/commands/dashboard/rm.rb +47 -0
  27. data/lib/gzr/commands/group.rb +87 -0
  28. data/lib/gzr/commands/group/ls.rb +73 -0
  29. data/lib/gzr/commands/group/member_groups.rb +74 -0
  30. data/lib/gzr/commands/group/member_users.rb +74 -0
  31. data/lib/gzr/commands/look.rb +75 -0
  32. data/lib/gzr/commands/look/cat.rb +55 -0
  33. data/lib/gzr/commands/look/import.rb +62 -0
  34. data/lib/gzr/commands/look/rm.rb +47 -0
  35. data/lib/gzr/commands/model.rb +51 -0
  36. data/lib/gzr/commands/model/ls.rb +72 -0
  37. data/lib/gzr/commands/plan.rb +149 -0
  38. data/lib/gzr/commands/plan/cat.rb +52 -0
  39. data/lib/gzr/commands/plan/disable.rb +49 -0
  40. data/lib/gzr/commands/plan/enable.rb +49 -0
  41. data/lib/gzr/commands/plan/failures.rb +98 -0
  42. data/lib/gzr/commands/plan/import.rb +69 -0
  43. data/lib/gzr/commands/plan/ls.rb +102 -0
  44. data/lib/gzr/commands/plan/rm.rb +47 -0
  45. data/lib/gzr/commands/plan/run.rb +58 -0
  46. data/lib/gzr/commands/query.rb +49 -0
  47. data/lib/gzr/commands/query/runquery.rb +102 -0
  48. data/lib/gzr/commands/role.rb +163 -0
  49. data/lib/gzr/commands/role/cat.rb +52 -0
  50. data/lib/gzr/commands/role/group_add.rb +51 -0
  51. data/lib/gzr/commands/role/group_ls.rb +76 -0
  52. data/lib/gzr/commands/role/group_rm.rb +51 -0
  53. data/lib/gzr/commands/role/ls.rb +75 -0
  54. data/lib/gzr/commands/role/rm.rb +47 -0
  55. data/lib/gzr/commands/role/user_add.rb +51 -0
  56. data/lib/gzr/commands/role/user_ls.rb +76 -0
  57. data/lib/gzr/commands/role/user_rm.rb +51 -0
  58. data/lib/gzr/commands/space.rb +137 -0
  59. data/lib/gzr/commands/space/cat.rb +53 -0
  60. data/lib/gzr/commands/space/create.rb +50 -0
  61. data/lib/gzr/commands/space/export.rb +117 -0
  62. data/lib/gzr/commands/space/ls.rb +97 -0
  63. data/lib/gzr/commands/space/rm.rb +56 -0
  64. data/lib/gzr/commands/space/top.rb +62 -0
  65. data/lib/gzr/commands/space/tree.rb +79 -0
  66. data/lib/gzr/commands/subcommandbase.rb +41 -0
  67. data/lib/gzr/commands/user.rb +111 -0
  68. data/lib/gzr/commands/user/cat.rb +52 -0
  69. data/lib/gzr/commands/user/disable.rb +47 -0
  70. data/lib/gzr/commands/user/enable.rb +47 -0
  71. data/lib/gzr/commands/user/ls.rb +82 -0
  72. data/lib/gzr/commands/user/me.rb +66 -0
  73. data/lib/gzr/modules/connection.rb +52 -0
  74. data/lib/gzr/modules/dashboard.rb +215 -0
  75. data/lib/gzr/modules/filehelper.rb +81 -0
  76. data/lib/gzr/modules/group.rb +93 -0
  77. data/lib/gzr/modules/look.rb +162 -0
  78. data/lib/gzr/modules/model.rb +40 -0
  79. data/lib/gzr/modules/plan.rb +216 -0
  80. data/lib/gzr/modules/role.rb +128 -0
  81. data/lib/gzr/modules/session.rb +203 -0
  82. data/lib/gzr/modules/space.rb +160 -0
  83. data/lib/gzr/modules/user.rb +114 -0
  84. data/lib/gzr/templates/.gitkeep +1 -0
  85. data/lib/gzr/templates/connection/dialects/.gitkeep +1 -0
  86. data/lib/gzr/templates/connection/ls/.gitkeep +1 -0
  87. data/lib/gzr/templates/dashboard/cat/.gitkeep +1 -0
  88. data/lib/gzr/templates/dashboard/import/.gitkeep +1 -0
  89. data/lib/gzr/templates/dashboard/rm/.gitkeep +1 -0
  90. data/lib/gzr/templates/group/ls/.gitkeep +1 -0
  91. data/lib/gzr/templates/group/member_groups/.gitkeep +1 -0
  92. data/lib/gzr/templates/group/member_users/.gitkeep +1 -0
  93. data/lib/gzr/templates/look/cat/.gitkeep +1 -0
  94. data/lib/gzr/templates/look/import/.gitkeep +1 -0
  95. data/lib/gzr/templates/look/rm/.gitkeep +1 -0
  96. data/lib/gzr/templates/model/ls/.gitkeep +1 -0
  97. data/lib/gzr/templates/plan/cat/.gitkeep +1 -0
  98. data/lib/gzr/templates/plan/disable/.gitkeep +1 -0
  99. data/lib/gzr/templates/plan/enable/.gitkeep +1 -0
  100. data/lib/gzr/templates/plan/failures/.gitkeep +1 -0
  101. data/lib/gzr/templates/plan/import/.gitkeep +1 -0
  102. data/lib/gzr/templates/plan/ls/.gitkeep +1 -0
  103. data/lib/gzr/templates/plan/rm/.gitkeep +1 -0
  104. data/lib/gzr/templates/plan/run/.gitkeep +1 -0
  105. data/lib/gzr/templates/query/run/.gitkeep +1 -0
  106. data/lib/gzr/templates/role/cat/.gitkeep +1 -0
  107. data/lib/gzr/templates/role/group_add/.gitkeep +1 -0
  108. data/lib/gzr/templates/role/group_ls/.gitkeep +1 -0
  109. data/lib/gzr/templates/role/group_rm/.gitkeep +1 -0
  110. data/lib/gzr/templates/role/ls/.gitkeep +1 -0
  111. data/lib/gzr/templates/role/rm/.gitkeep +1 -0
  112. data/lib/gzr/templates/role/user_add/.gitkeep +1 -0
  113. data/lib/gzr/templates/role/user_ls/.gitkeep +1 -0
  114. data/lib/gzr/templates/role/user_rm/.gitkeep +1 -0
  115. data/lib/gzr/templates/space/cat/.gitkeep +1 -0
  116. data/lib/gzr/templates/space/create/.gitkeep +1 -0
  117. data/lib/gzr/templates/space/export/.gitkeep +1 -0
  118. data/lib/gzr/templates/space/ls/.gitkeep +1 -0
  119. data/lib/gzr/templates/space/rm/.gitkeep +1 -0
  120. data/lib/gzr/templates/space/top/.gitkeep +1 -0
  121. data/lib/gzr/templates/space/tree/.gitkeep +1 -0
  122. data/lib/gzr/templates/user/cat/.gitkeep +1 -0
  123. data/lib/gzr/templates/user/disable/.gitkeep +1 -0
  124. data/lib/gzr/templates/user/enable/.gitkeep +1 -0
  125. data/lib/gzr/templates/user/ls/.gitkeep +1 -0
  126. data/lib/gzr/templates/user/me/.gitkeep +1 -0
  127. data/lib/gzr/version.rb +24 -0
  128. metadata +325 -0
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1,69 @@
1
+ # The MIT License (MIT)
2
+
3
+ # Copyright (c) 2018 Mike DeAngelo Looker Data Sciences, Inc.
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # frozen_string_literal: true
23
+
24
+ require_relative 'subcommandbase'
25
+
26
+ module Gzr
27
+ module Commands
28
+ class Connection < SubCommandBase
29
+
30
+ namespace :connection
31
+
32
+ desc 'dialects', 'List all available dialects'
33
+ method_option :help, aliases: '-h', type: :boolean,
34
+ desc: 'Display usage information'
35
+ method_option :fields, type: :string, default: 'name,label',
36
+ desc: 'Fields to display'
37
+ method_option :plain, type: :boolean, default: false,
38
+ desc: 'print without any extra formatting'
39
+ method_option :csv, type: :boolean, default: false,
40
+ desc: 'output in csv format per RFC4180'
41
+ def dialects(*)
42
+ if options[:help]
43
+ invoke :help, ['dialects']
44
+ else
45
+ require_relative 'connection/dialects'
46
+ Gzr::Commands::Connection::Dialects.new(options).execute
47
+ end
48
+ end
49
+
50
+ desc 'ls', 'List all available connections'
51
+ method_option :help, aliases: '-h', type: :boolean,
52
+ desc: 'Display usage information'
53
+ method_option :fields, type: :string, default: 'name,dialect(name),host,port,database,schema',
54
+ desc: 'Fields to display'
55
+ method_option :plain, type: :boolean, default: false,
56
+ desc: 'print without any extra formatting'
57
+ method_option :csv, type: :boolean, default: false,
58
+ desc: 'output in csv format per RFC4180'
59
+ def ls(*)
60
+ if options[:help]
61
+ invoke :help, ['ls']
62
+ else
63
+ require_relative 'connection/ls'
64
+ Gzr::Commands::Connection::Ls.new(options).execute
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,72 @@
1
+ # The MIT License (MIT)
2
+
3
+ # Copyright (c) 2018 Mike DeAngelo Looker Data Sciences, Inc.
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # frozen_string_literal: true
23
+
24
+ require_relative '../../command'
25
+ require_relative '../../modules/connection'
26
+ require 'tty-table'
27
+
28
+ module Gzr
29
+ module Commands
30
+ class Connection
31
+ class Dialects < Gzr::Command
32
+ include Gzr::Connection
33
+ def initialize(options)
34
+ super()
35
+ @options = options
36
+ end
37
+
38
+ def execute(input: $stdin, output: $stdout)
39
+ say_warning(@options) if @options[:debug]
40
+ with_session do
41
+ data = query_all_dialects(@options[:fields])
42
+ begin
43
+ say_ok "No dialects found"
44
+ return nil
45
+ end unless data && data.length > 0
46
+
47
+ table_hash = Hash.new
48
+ fields = field_names(@options[:fields])
49
+ table_hash[:header] = data[0].to_attrs.keys unless @options[:plain]
50
+ expressions = fields.collect { |fn| field_expression(fn) }
51
+ table_hash[:rows] = data.map do |row|
52
+ expressions.collect do |e|
53
+ eval "row.#{e}"
54
+ end
55
+ end
56
+ table = TTY::Table.new(table_hash)
57
+ alignments = fields.collect do |k|
58
+ (k =~ /id$/) ? :right : :left
59
+ end
60
+ begin
61
+ if @options[:csv] then
62
+ output.puts render_csv(table)
63
+ else
64
+ output.puts table.render(if @options[:plain] then :basic else :ascii end, alignments: alignments)
65
+ end
66
+ end if table
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,72 @@
1
+ # The MIT License (MIT)
2
+
3
+ # Copyright (c) 2018 Mike DeAngelo Looker Data Sciences, Inc.
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # frozen_string_literal: true
23
+
24
+ require_relative '../../command'
25
+ require_relative '../../modules/connection'
26
+ require 'tty-table'
27
+
28
+ module Gzr
29
+ module Commands
30
+ class Connection
31
+ class Ls < Gzr::Command
32
+ include Gzr::Connection
33
+ def initialize(options)
34
+ super()
35
+ @options = options
36
+ end
37
+
38
+ def execute(input: $stdin, output: $stdout)
39
+ say_warning(@options) if @options[:debug]
40
+ with_session do
41
+ data = query_all_connections(@options[:fields])
42
+ begin
43
+ say_ok "No connections found"
44
+ return nil
45
+ end unless data && data.length > 0
46
+
47
+ table_hash = Hash.new
48
+ fields = field_names(@options[:fields])
49
+ table_hash[:header] = fields unless @options[:plain]
50
+ expressions = fields.collect { |fn| field_expression(fn) }
51
+ table_hash[:rows] = data.map do |row|
52
+ expressions.collect do |e|
53
+ eval "row.#{e}"
54
+ end
55
+ end
56
+ table = TTY::Table.new(table_hash)
57
+ alignments = fields.collect do |k|
58
+ (k =~ /id$/) ? :right : :left
59
+ end
60
+ begin
61
+ if @options[:csv] then
62
+ output.puts render_csv(table)
63
+ else
64
+ output.puts table.render(if @options[:plain] then :basic else :ascii end, alignments: alignments, width: 1024)
65
+ end
66
+ end if table
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,75 @@
1
+ # The MIT License (MIT)
2
+
3
+ # Copyright (c) 2018 Mike DeAngelo Looker Data Sciences, Inc.
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # frozen_string_literal: true
23
+
24
+ require_relative 'subcommandbase'
25
+
26
+ module Gzr
27
+ module Commands
28
+ class Dashboard < SubCommandBase
29
+
30
+ namespace :dashboard
31
+
32
+ desc 'cat DASHBOARD_ID', 'Output the JSON representation of a dashboard to the screen or a file'
33
+ method_option :help, aliases: '-h', type: :boolean,
34
+ desc: 'Display usage information'
35
+ method_option :dir, type: :string,
36
+ desc: 'Directory to store output file'
37
+ method_option :plans, type: :boolean,
38
+ desc: 'Include scheduled plans'
39
+ def cat(dashboard_id)
40
+ if options[:help]
41
+ invoke :help, ['cat']
42
+ else
43
+ require_relative 'dashboard/cat'
44
+ Gzr::Commands::Dashboard::Cat.new(dashboard_id, options).execute
45
+ end
46
+ end
47
+
48
+ desc 'import FILE DEST_SPACE_ID', 'Import a dashboard from a file'
49
+ method_option :help, aliases: '-h', type: :boolean,
50
+ desc: 'Display usage information'
51
+ method_option :plain, type: :boolean,
52
+ desc: 'Provide minimal response information'
53
+ def import(file,dest_space_id)
54
+ if options[:help]
55
+ invoke :help, ['import']
56
+ else
57
+ require_relative 'dashboard/import'
58
+ Gzr::Commands::Dashboard::Import.new(file, dest_space_id, options).execute
59
+ end
60
+ end
61
+
62
+ desc 'rm DASHBOARD_ID', 'Remove or delete the given dashboard'
63
+ method_option :help, aliases: '-h', type: :boolean,
64
+ desc: 'Display usage information'
65
+ def rm(id)
66
+ if options[:help]
67
+ invoke :help, ['rm']
68
+ else
69
+ require_relative 'dashboard/rm'
70
+ Gzr::Commands::Dashboard::Rm.new(id, options).execute
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,67 @@
1
+ # The MIT License (MIT)
2
+
3
+ # Copyright (c) 2018 Mike DeAngelo Looker Data Sciences, Inc.
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # frozen_string_literal: true
23
+
24
+ require 'json'
25
+ require_relative '../../command'
26
+ require_relative '../../modules/dashboard'
27
+ require_relative '../../modules/plan'
28
+ require_relative '../../modules/filehelper'
29
+
30
+ module Gzr
31
+ module Commands
32
+ class Dashboard
33
+ class Cat < Gzr::Command
34
+ include Gzr::Dashboard
35
+ include Gzr::FileHelper
36
+ include Gzr::Plan
37
+ def initialize(dashboard_id,options)
38
+ super()
39
+ @dashboard_id = dashboard_id
40
+ @options = options
41
+ end
42
+
43
+ def execute(*args, input: $stdin, output: $stdout)
44
+ say_warning("options: #{@options.inspect}") if @options[:debug]
45
+ with_session("3.1") do
46
+ data = query_dashboard(@dashboard_id)
47
+ data.to_attrs()[:dashboard_elements].each_index do |i|
48
+ element = data[:dashboard_elements][i]
49
+ if element[:merge_result_id]
50
+ merge_result = merge_query(element[:merge_result_id])
51
+ merge_result[:source_queries].each_index do |j|
52
+ source_query = merge_result[:source_queries][j]
53
+ merge_result[:source_queries][j][:query] = query(source_query[:query_id])
54
+ end
55
+ data[:dashboard_elements][i][:merge_result] = merge_result
56
+ end
57
+ end
58
+ data[:scheduled_plans] = query_scheduled_plans_for_dashboard(@dashboard_id,"all") if @options[:plans]
59
+ write_file(@options[:dir] ? "Dashboard_#{data.id}_#{data.title}.json" : nil, @options[:dir], nil, output) do |f|
60
+ f.puts JSON.pretty_generate(data.to_attrs)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,256 @@
1
+ # The MIT License (MIT)
2
+
3
+ # Copyright (c) 2018 Mike DeAngelo Looker Data Sciences, Inc.
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the "Software"), to deal in
7
+ # the Software without restriction, including without limitation the rights to
8
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ # the Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # frozen_string_literal: true
23
+
24
+ require_relative '../../../gzr'
25
+ require_relative '../../command'
26
+ require_relative '../../modules/dashboard'
27
+ require_relative '../../modules/look'
28
+ require_relative '../../modules/user'
29
+ require_relative '../../modules/plan'
30
+ require_relative '../../modules/filehelper'
31
+
32
+ module Gzr
33
+ module Commands
34
+ class Dashboard
35
+ class Import < Gzr::Command
36
+ include Gzr::Dashboard
37
+ include Gzr::Look
38
+ include Gzr::User
39
+ include Gzr::Plan
40
+ include Gzr::FileHelper
41
+ def initialize(file, dest_space_id, options)
42
+ super()
43
+ @file = file
44
+ @dest_space_id = dest_space_id
45
+ @options = options
46
+ end
47
+
48
+ def execute(input: $stdin, output: $stdout)
49
+ say_warning("options: #{@options.inspect}") if @options[:debug]
50
+ with_session("3.1") do
51
+
52
+ @me ||= query_me("id")
53
+
54
+ read_file(@file) do |data|
55
+
56
+ dashboard = sync_dashboard(data,@dest_space_id)
57
+
58
+ source_filters = data[:dashboard_filters].sort { |a,b| a[:row] <=> b[:row] }
59
+ existing_filters = dashboard.dashboard_filters.sort { |a,b| a.row <=> b.row }
60
+ existing_filters.collect! do |e|
61
+ matches_by_name_title = source_filters.select { |s| s[:row] != e.row && (s[:title] == e.title || s[:name] == e.name) }
62
+ if matches_by_name_title.length > 0
63
+ delete_dashboard_filter(e.id)
64
+ nil
65
+ else
66
+ e
67
+ end
68
+ end
69
+ pairs(source_filters,existing_filters,dashboard.id) do |source,target,id|
70
+ say_warning "Synching dashboard filter for dashboard #{id}" if @options[:debug]
71
+ sync_dashboard_filter(source,target,id)
72
+ end
73
+
74
+ elem_table = pairs(data[:dashboard_elements],dashboard.dashboard_elements,dashboard.id) do |source,target,id|
75
+ sync_dashboard_element(source,target,id)
76
+ end
77
+
78
+ source_dashboard_layouts = data[:dashboard_layouts].sort_by { |v| (v[:active] ? 0 : 1) }
79
+ existing_dashboard_layouts = dashboard.dashboard_layouts.sort_by { |v| (v.active ? 0 : 1) }
80
+ pairs(source_dashboard_layouts,existing_dashboard_layouts) do |s,t|
81
+ sync_dashboard_layout(dashboard.id,s,t) do |s,t|
82
+ sync_dashboard_layout_component(s,t,elem_table)
83
+ end
84
+ end
85
+ upsert_plans_for_dashboard(dashboard.id,@me.id,data[:scheduled_plans]) if data[:scheduled_plans]
86
+ output.puts "Imported dashboard #{dashboard.id}" unless @options[:plain]
87
+ output.puts dashboard.id if @options[:plain]
88
+ end
89
+ end
90
+ end
91
+
92
+ def sync_dashboard(source,target_space_id)
93
+ existing_dashboard = search_dashboards_by_title(source[:title], target_space_id).fetch(0,nil)
94
+ slug_used = search_dashboards_by_slug(source[:slug]).fetch(0,nil) if source[:slug]
95
+
96
+ if slug_used then
97
+ if existing_dashboard then
98
+ if !(existing_dashboard.space_id == slug_used.space_id && existing_dashboard.title == slug_used.title) then
99
+ say_warning "slug #{slug_used.slug} already used for dashboard #{slug_used.title} in space #{slug_used.space_id}"
100
+ say_warning "dashboard will be imported with new slug"
101
+ end
102
+ else
103
+ say_warning "slug #{slug_used.slug} already used for dashboard #{slug_used.title} in space #{slug_used.space_id}"
104
+ say_warning "dashboard will be imported with new slug"
105
+ end
106
+ end
107
+
108
+ if existing_dashboard then
109
+ if @options[:force] then
110
+ say_ok "Modifying existing dashboard #{existing_dashboard.id} #{existing_dashboard[:title]} in space #{target_space_id}"
111
+ new_dash = source.select do |k,v|
112
+ (keys_to_keep('update_dashboard') - [:space_id,:user_id,:title,:slug]).include? k
113
+ end
114
+ new_dash[:slug] = source[:slug] unless slug_used
115
+ return update_dashboard(existing_dashboard.id,new_dash)
116
+ else
117
+ raise Gzr::CLI::Error, "Dashboard #{source[:title]} already exists in space #{target_space_id}\nUse --force if you want to overwrite it"
118
+ end
119
+ else
120
+ new_dash = source.select do |k,v|
121
+ (keys_to_keep('create_dashboard') - [:space_id,:user_id,:slug]).include? k
122
+ end
123
+ new_dash[:slug] = source[:slug] unless slug_used
124
+ new_dash[:space_id] = target_space_id
125
+ new_dash[:user_id] = @me.id
126
+ return create_dashboard(new_dash)
127
+ end
128
+ end
129
+
130
+ def sync_dashboard_filter(new_filter,existing_filter,dashboard_id)
131
+ if new_filter && !existing_filter then
132
+ filter = new_filter.select do |k,v|
133
+ (keys_to_keep('create_dashboard_filter') + [:row]).include? k
134
+ end
135
+ filter[:dashboard_id] = dashboard_id
136
+ say_warning "Creating filter" if @options[:debug]
137
+ return create_dashboard_filter(filter)
138
+ end
139
+ if existing_filter && new_filter then
140
+ filter = new_filter.select do |k,v|
141
+ (keys_to_keep('update_dashboard_filter') + [:row]).include? k
142
+ end
143
+ say_warning "Updating filter #{existing_filter.id}" if @options[:debug]
144
+ return update_dashboard_filter(existing_filter.id,filter)
145
+ end
146
+ say_warning "Deleting filter #{existing_filter.id}" if @options[:debug]
147
+ return delete_dashboard_filter(existing_filter.id)
148
+ end
149
+
150
+ def copy_result_maker_filterables(new_element)
151
+ return nil unless new_element[:result_maker]
152
+ if new_element[:result_maker].fetch(:filterables,[]).length > 0
153
+ result_maker = { :filterables => [] }
154
+ new_element[:result_maker][:filterables].each do |filterable|
155
+ result_maker[:filterables] << filterable.select do |k,v|
156
+ true unless [:can].include? k
157
+ end
158
+ end
159
+ return result_maker
160
+ end
161
+ nil
162
+ end
163
+
164
+ def sync_dashboard_element(new_element,existing_element,dashboard_id)
165
+ if new_element && !existing_element then
166
+ element = new_element.select do |k,v|
167
+ (keys_to_keep('create_dashboard_element') - [:dashboard_id, :look_id, :query_id, :merge_result_id]).include? k
168
+ end
169
+ (element[:query_id],element[:look_id],element[:merge_result_id]) = process_dashboard_element(new_element)
170
+ say_warning "Creating dashboard element #{element.inspect}" if @options[:debug]
171
+ element[:dashboard_id] = dashboard_id
172
+ result_maker = copy_result_maker_filterables(new_element)
173
+ element[:result_maker] = result_maker if result_maker
174
+ return [new_element[:id], create_dashboard_element(element).id]
175
+ end
176
+ if existing_element && new_element then
177
+ element = keys_to_keep('update_dashboard_element').collect do |e|
178
+ [e,nil]
179
+ end.to_h
180
+
181
+ element.merge!( new_element.select do |k,v|
182
+ (keys_to_keep('update_dashboard_element') - [:dashboard_id, :look_id, :query_id, :merge_result_id]).include? k
183
+ end
184
+ )
185
+ (element[:query_id],element[:look_id],element[:merge_result_id]) = process_dashboard_element(new_element)
186
+ say_warning "Updating dashboard element #{existing_element.id}" if @options[:debug]
187
+ result_maker = copy_result_maker_filterables(new_element)
188
+ element[:result_maker] = result_maker if result_maker
189
+ return [new_element[:id], update_dashboard_element(existing_element.id,element).id]
190
+ end
191
+ say_warning "Deleting dashboard element #{existing_element.id}" if @options[:debug]
192
+ delete_dashboard_element(existing_element.id)
193
+ return [nil,existing_element.id]
194
+ end
195
+
196
+ def process_dashboard_element(dash_elem)
197
+ return [create_fetch_query(dash_elem[:query]).id, nil, nil] if dash_elem[:query]
198
+ return [nil, upsert_look(@me.id, create_fetch_query(dash_elem[:look][:query]).id, @dest_space_id, dash_elem[:look]).id, nil] if dash_elem[:look]
199
+ return [nil,nil,create_merge_result(dash_elem[:merge_result]).id] if dash_elem[:merge_result]
200
+ [nil,nil,nil]
201
+ end
202
+
203
+ def sync_dashboard_layout(dashboard_id,new_layout,existing_layout)
204
+ layout_obj = nil
205
+ if new_layout && !existing_layout then
206
+ layout = new_layout.select do |k,v|
207
+ (keys_to_keep('create_dashboard_layout') - [:dashboard_id]).include? k
208
+ end
209
+ layout[:dashboard_id] = dashboard_id
210
+ say_warning "Creating dashboard layout #{layout}" if @options[:debug]
211
+ layout_obj = create_dashboard_layout(layout)
212
+ end
213
+ if new_layout && existing_layout then
214
+ layout = new_layout.select do |k,v|
215
+ (keys_to_keep('update_dashboard_layout') - [:dashboard_id]).include? k
216
+ end
217
+ say_warning "Updating dashboard layout #{existing_layout.id}" if @options[:debug]
218
+ layout_obj = update_dashboard_layout(existing_layout.id,layout)
219
+ end
220
+ if !new_layout && existing_layout then
221
+ say_warning "Deleting dashboard layout #{existing_layout.id}" if @options[:debug]
222
+ delete_dashboard_layout(existing_layout.id)
223
+ end
224
+
225
+ return unless layout_obj
226
+
227
+ #say_warning "new_layout[:active] is #{new_layout&.fetch(:active)} for #{layout_obj.id}"
228
+ #if layout_obj && new_layout&.fetch(:active,false)
229
+ # say_warning "Setting layout #{layout_obj.id} active"
230
+ # update_dashboard_layout(layout_obj.id, { :active => true })
231
+ #end
232
+
233
+ layout_components = new_layout[:dashboard_layout_components].zip(layout_obj.dashboard_layout_components)
234
+ return layout_components unless block_given?
235
+
236
+ layout_components.each { |s,t| yield(s,t) }
237
+ end
238
+
239
+ def sync_dashboard_layout_component(source, target, elem_table)
240
+ component = keys_to_keep('update_dashboard_layout_component').collect do |e|
241
+ [e,nil]
242
+ end.to_h
243
+ component[:dashboard_layout_id] = target.dashboard_layout_id
244
+
245
+ component.merge!(source.select do |k,v|
246
+ (keys_to_keep('update_dashboard_layout_component') - [:id,:dashboard_layout_id]).include? k
247
+ end)
248
+
249
+ component[:dashboard_element_id] = elem_table.assoc(source[:dashboard_element_id])[1]
250
+ say_warning "Updating dashboard layout component #{target.id}" if @options[:debug]
251
+ update_dashboard_layout_component(target.id,component)
252
+ end
253
+ end
254
+ end
255
+ end
256
+ end