gooddata 0.6.10 → 0.6.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +6 -0
- data/README.md +1 -0
- data/gooddata.gemspec +38 -40
- data/lib/gooddata/bricks/base_downloader.rb +1 -1
- data/lib/gooddata/bricks/middleware/base_middleware.rb +36 -0
- data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +8 -38
- data/lib/gooddata/bricks/middleware/decode_params_middleware.rb +14 -0
- data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +7 -6
- data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +7 -5
- data/lib/gooddata/bricks/middleware/logger_middleware.rb +1 -1
- data/lib/gooddata/bricks/middleware/restforce_middleware.rb +20 -14
- data/lib/gooddata/bricks/middleware/undot_params_middleware.rb +33 -0
- data/lib/gooddata/cli/commands/api_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/auth_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/console_cmd.rb +2 -2
- data/lib/gooddata/cli/commands/process_cmd.rb +54 -7
- data/lib/gooddata/cli/commands/project_cmd.rb +9 -9
- data/lib/gooddata/cli/commands/projects_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/run_ruby_cmd.rb +24 -7
- data/lib/gooddata/cli/commands/scaffold_cmd.rb +2 -2
- data/lib/gooddata/cli/commands/user_cmd.rb +1 -1
- data/lib/gooddata/cli/hooks.rb +3 -3
- data/lib/gooddata/commands/datasets.rb +1 -1
- data/lib/gooddata/commands/project.rb +2 -2
- data/lib/gooddata/commands/role.rb +1 -1
- data/lib/gooddata/commands/runners.rb +2 -2
- data/lib/gooddata/connection.rb +2 -2
- data/lib/gooddata/core/nil_logger.rb +1 -1
- data/lib/gooddata/core/rest.rb +12 -8
- data/lib/gooddata/data/guesser.rb +1 -1
- data/lib/gooddata/exceptions/attr_element_not_found.rb +1 -1
- data/lib/gooddata/extensions/enumerable.rb +1 -1
- data/lib/gooddata/extensions/hash.rb +20 -0
- data/lib/gooddata/helpers/csv_helper.rb +1 -1
- data/lib/gooddata/helpers/global_helpers.rb +59 -1
- data/lib/gooddata/mixins/md_lock.rb +83 -0
- data/lib/gooddata/mixins/md_object_indexer.rb +1 -1
- data/lib/gooddata/mixins/md_object_query.rb +1 -1
- data/lib/gooddata/mixins/md_relations.rb +0 -9
- data/lib/gooddata/models/dashboard_builder.rb +1 -1
- data/lib/gooddata/models/domain.rb +2 -2
- data/lib/gooddata/models/empty_result.rb +5 -5
- data/lib/gooddata/models/execution.rb +74 -0
- data/lib/gooddata/models/execution_detail.rb +74 -0
- data/lib/gooddata/models/membership.rb +1 -1
- data/lib/gooddata/models/metadata/attribute.rb +4 -6
- data/lib/gooddata/models/metadata/dashboard.rb +2 -0
- data/lib/gooddata/models/metadata/fact.rb +2 -2
- data/lib/gooddata/models/metadata/metric.rb +4 -1
- data/lib/gooddata/models/metadata/report.rb +84 -34
- data/lib/gooddata/models/metadata/report_definition.rb +28 -17
- data/lib/gooddata/models/metadata.rb +1 -1
- data/lib/gooddata/models/model.rb +1 -1
- data/lib/gooddata/models/process.rb +70 -54
- data/lib/gooddata/models/profile.rb +47 -10
- data/lib/gooddata/models/project.rb +74 -30
- data/lib/gooddata/models/project_blueprint.rb +9 -10
- data/lib/gooddata/models/project_builder.rb +2 -2
- data/lib/gooddata/models/project_creator.rb +4 -4
- data/lib/gooddata/models/report_data_result.rb +1 -1
- data/lib/gooddata/models/schedule.rb +39 -32
- data/lib/gooddata/models/to_manifest.rb +5 -5
- data/lib/gooddata/models/to_wire.rb +3 -3
- data/lib/gooddata/rest/client.rb +64 -31
- data/lib/gooddata/rest/connection.rb +7 -7
- data/lib/gooddata/rest/connections/dummy_connection.rb +5 -5
- data/lib/gooddata/rest/connections/rest_client_connection.rb +106 -44
- data/lib/gooddata/rest/object.rb +1 -1
- data/lib/gooddata/version.rb +1 -1
- data/spec/bricks/bricks_spec.rb +67 -0
- data/spec/bricks/default-config.json +8 -0
- data/spec/data/gooddata_version_process/gooddata_version.rb +3 -0
- data/spec/data/gooddata_version_process/gooddata_version.zip +0 -0
- data/spec/data/ruby_params_process/ruby_params.rb +3 -0
- data/spec/helpers/process_helper.rb +12 -0
- data/spec/helpers/schedule_helper.rb +21 -0
- data/spec/integration/create_project_spec.rb +19 -0
- data/spec/integration/full_process_schedule_spec.rb +129 -8
- data/spec/integration/full_project_spec.rb +52 -2
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/core/rest_spec.rb +76 -3
- data/spec/unit/helpers_spec.rb +43 -0
- data/spec/unit/models/metric_spec.rb +33 -0
- data/spec/unit/models/params_spec.rb +96 -0
- data/spec/unit/models/profile_spec.rb +16 -0
- data/spec/unit/models/schedule_spec.rb +12 -3
- metadata +350 -187
- data/lib/gooddata/helper/class_helper.rb +0 -1
- data/lib/gooddata/helper/helpers.rb +0 -8
@@ -13,7 +13,7 @@ GoodData::CLI.module_eval do
|
|
13
13
|
command :project do |c|
|
14
14
|
c.desc 'If you are in a gooddata project blueprint or if you provide a project id it will start an interactive session inside that project'
|
15
15
|
c.command :jack_in do |jack|
|
16
|
-
jack.action do |global_options, options,
|
16
|
+
jack.action do |global_options, options, _args|
|
17
17
|
opts = options.merge(global_options)
|
18
18
|
GoodData::Command::Project.jack_in(opts)
|
19
19
|
end
|
@@ -44,7 +44,7 @@ GoodData::CLI.module_eval do
|
|
44
44
|
|
45
45
|
c.desc 'Delete a project. Be careful this is impossible to revert'
|
46
46
|
c.command :delete do |delete|
|
47
|
-
delete.action do |global_options, options,
|
47
|
+
delete.action do |global_options, options, _args|
|
48
48
|
id = global_options[:project_id]
|
49
49
|
opts = options.merge(global_options)
|
50
50
|
client = GoodData.connect(opts)
|
@@ -66,7 +66,7 @@ GoodData::CLI.module_eval do
|
|
66
66
|
clone.default_value true
|
67
67
|
clone.switch [:d, :data]
|
68
68
|
|
69
|
-
clone.action do |global_options, options,
|
69
|
+
clone.action do |global_options, options, _args|
|
70
70
|
opts = options.merge(global_options)
|
71
71
|
id = global_options[:project_id]
|
72
72
|
token = opts[:token]
|
@@ -103,7 +103,7 @@ GoodData::CLI.module_eval do
|
|
103
103
|
|
104
104
|
c.desc 'List users'
|
105
105
|
c.command :users do |list|
|
106
|
-
list.action do |global_options, options,
|
106
|
+
list.action do |global_options, options, _args|
|
107
107
|
opts = options.merge(global_options)
|
108
108
|
client = GoodData.connect(opts)
|
109
109
|
|
@@ -117,7 +117,7 @@ GoodData::CLI.module_eval do
|
|
117
117
|
|
118
118
|
c.desc 'Shows basic info about a project'
|
119
119
|
c.command :show do |show|
|
120
|
-
show.action do |global_options, options,
|
120
|
+
show.action do |global_options, options, _args|
|
121
121
|
id = global_options[:project_id]
|
122
122
|
opts = options.merge(global_options)
|
123
123
|
client = GoodData.connect(opts)
|
@@ -128,7 +128,7 @@ GoodData::CLI.module_eval do
|
|
128
128
|
|
129
129
|
c.desc 'If you are in a gooddata project blueprint it will apply the changes. If you do not provide a project id it will build it from scratch and create a project for you.'
|
130
130
|
c.command :build do |show|
|
131
|
-
show.action do |global_options, options,
|
131
|
+
show.action do |global_options, options, _args|
|
132
132
|
opts = options.merge(global_options)
|
133
133
|
client = GoodData.connect(opts)
|
134
134
|
spec, _ = GoodData::Command::Project.get_spec_and_project_id('.')
|
@@ -139,7 +139,7 @@ GoodData::CLI.module_eval do
|
|
139
139
|
|
140
140
|
c.desc 'If you are in a gooddata project blueprint it will apply the changes. If you do not provide a project id it will build it from scratch and create a project for you.'
|
141
141
|
c.command :update do |show|
|
142
|
-
show.action do |global_options, options,
|
142
|
+
show.action do |global_options, options, _args|
|
143
143
|
|
144
144
|
opts = options.merge(global_options)
|
145
145
|
GoodData.connect(opts)
|
@@ -153,7 +153,7 @@ GoodData::CLI.module_eval do
|
|
153
153
|
|
154
154
|
c.desc 'Shows roles in the project'
|
155
155
|
c.command :roles do |roles|
|
156
|
-
roles.action do |global_options, options,
|
156
|
+
roles.action do |global_options, options, _args|
|
157
157
|
project_id = global_options[:project_id]
|
158
158
|
fail 'Project ID has to be provided' if project_id.nil? || project_id.empty?
|
159
159
|
|
@@ -167,7 +167,7 @@ GoodData::CLI.module_eval do
|
|
167
167
|
|
168
168
|
c.desc 'You can run project validation which will check RI and other problems.'
|
169
169
|
c.command :validate do |show|
|
170
|
-
show.action do |global_options, options,
|
170
|
+
show.action do |global_options, options, _args|
|
171
171
|
opts = options.merge(global_options)
|
172
172
|
client = GoodData.connect(opts)
|
173
173
|
pp GoodData::Command::Project.validate(global_options[:project_id], opts.merge(client: client))
|
@@ -10,7 +10,7 @@ GoodData::CLI.module_eval do
|
|
10
10
|
|
11
11
|
c.desc "Lists user's projects"
|
12
12
|
c.command :list do |list|
|
13
|
-
list.action do |global_options, options,
|
13
|
+
list.action do |global_options, options, _args|
|
14
14
|
opts = options.merge(global_options)
|
15
15
|
client = GoodData.connect(opts)
|
16
16
|
list = GoodData::Command::Projects.list(client: client)
|
@@ -1,16 +1,23 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
require 'pp'
|
4
|
+
require 'hashie'
|
4
5
|
|
5
6
|
require_relative '../shared'
|
6
7
|
require_relative '../../commands/process'
|
7
8
|
require_relative '../../commands/runners'
|
8
9
|
require_relative '../../client'
|
9
10
|
|
11
|
+
# translate given params (with dots) to json-like params
|
12
|
+
def load_undot(filename)
|
13
|
+
p = MultiJson.load(File.read(filename)).extend(Hashie::Extensions::DeepMerge)
|
14
|
+
p.undot
|
15
|
+
end
|
16
|
+
|
10
17
|
GoodData::CLI.module_eval do
|
11
18
|
|
12
19
|
desc 'Run ruby bricks either locally or remotely deployed on our server. Currently private alpha.'
|
13
|
-
# arg_name 'show'
|
20
|
+
# arg_name 'show'
|
14
21
|
command :run_ruby do |c|
|
15
22
|
|
16
23
|
c.desc 'Directory of the ruby brick'
|
@@ -21,10 +28,14 @@ GoodData::CLI.module_eval do
|
|
21
28
|
c.default_value nil
|
22
29
|
c.flag [:l, :logger]
|
23
30
|
|
24
|
-
c.desc 'Params file path. Inside should be hash of key values'
|
31
|
+
c.desc 'Params file path. Inside should be hash of key values. These params override any defaults given in bricks.'
|
25
32
|
c.default_value nil
|
26
33
|
c.flag [:params]
|
27
34
|
|
35
|
+
c.desc 'Remote system credentials file path. Inside should be hash of key values.'
|
36
|
+
c.default_value nil
|
37
|
+
c.flag [:credentials]
|
38
|
+
|
28
39
|
c.desc 'Run on remote machine'
|
29
40
|
c.switch [:r, :remote]
|
30
41
|
|
@@ -32,14 +43,21 @@ GoodData::CLI.module_eval do
|
|
32
43
|
c.default_value nil
|
33
44
|
c.flag [:n, :name]
|
34
45
|
|
35
|
-
c.action do |global_options, options,
|
46
|
+
c.action do |global_options, options, _args|
|
36
47
|
verbose = global_options[:verbose]
|
37
48
|
options[:expanded_params] = if options[:params]
|
38
|
-
|
49
|
+
# load params and credentials if given
|
50
|
+
runtime_params = load_undot(options[:params])
|
51
|
+
if options[:credentials]
|
52
|
+
runtime_params = runtime_params.deep_merge(load_undot(options[:credentials]))
|
53
|
+
end
|
54
|
+
{ 'config' => runtime_params }
|
39
55
|
else
|
40
|
-
{}
|
56
|
+
{ 'config' => {} }
|
41
57
|
end
|
42
|
-
|
58
|
+
# if there are some GDC_* params in config, put them on the level above
|
59
|
+
gdc_params = options[:expanded_params]['config'].select { |k, _| k =~ /GDC_.*/ }
|
60
|
+
options[:expanded_params].merge!(gdc_params)
|
43
61
|
opts = options.merge(global_options).merge(:type => 'RUBY')
|
44
62
|
GoodData.connect(opts)
|
45
63
|
if options[:remote]
|
@@ -53,5 +71,4 @@ GoodData::CLI.module_eval do
|
|
53
71
|
puts HighLine.color('Running ruby brick - DONE', HighLine::GREEN) if verbose
|
54
72
|
end
|
55
73
|
end
|
56
|
-
|
57
74
|
end
|
@@ -13,7 +13,7 @@ GoodData::CLI.module_eval do
|
|
13
13
|
|
14
14
|
c.desc 'Scaffold a gooddata project blueprint'
|
15
15
|
c.command :project do |project|
|
16
|
-
project.action do |
|
16
|
+
project.action do |_global_options, _options, args|
|
17
17
|
name = args.first
|
18
18
|
fail 'Name of the project has to be provided' if name.nil? || name.empty?
|
19
19
|
GoodData::Command::Scaffold.project(name)
|
@@ -23,7 +23,7 @@ GoodData::CLI.module_eval do
|
|
23
23
|
c.desc 'Scaffold a gooddata ruby brick. This is a piece of code that you can run on our platform'
|
24
24
|
c.command :brick do |brick|
|
25
25
|
# brick.arg_name 'name'
|
26
|
-
brick.action do |
|
26
|
+
brick.action do |_global_options, _options, args|
|
27
27
|
name = args.first
|
28
28
|
fail 'Name of the brick has to be provided' if name.nil? || name.empty?
|
29
29
|
GoodData::Command::Scaffold.brick(name)
|
@@ -11,7 +11,7 @@ GoodData::CLI.module_eval do
|
|
11
11
|
command :user do |c|
|
12
12
|
c.desc 'Show your profile'
|
13
13
|
c.command :show do |show|
|
14
|
-
show.action do |global_options, options,
|
14
|
+
show.action do |global_options, options, _args|
|
15
15
|
opts = options.merge(global_options)
|
16
16
|
client = GoodData.connect(opts)
|
17
17
|
pp GoodData::Command::User.show(client: client)
|
data/lib/gooddata/cli/hooks.rb
CHANGED
@@ -6,7 +6,7 @@ require 'pp'
|
|
6
6
|
require_relative '../helpers/auth_helpers'
|
7
7
|
|
8
8
|
GoodData::CLI.module_eval do
|
9
|
-
pre do |global,
|
9
|
+
pre do |global, _command, _options, _args|
|
10
10
|
require 'logger'
|
11
11
|
GoodData.logger = Logger.new(STDOUT) if global[:l]
|
12
12
|
username = global[:username]
|
@@ -30,13 +30,13 @@ GoodData::CLI.module_eval do
|
|
30
30
|
true
|
31
31
|
end
|
32
32
|
|
33
|
-
post do |
|
33
|
+
post do |_global, _command, _options, _args|
|
34
34
|
# Post logic here
|
35
35
|
# Use skips_post before a command to skip this
|
36
36
|
# block on that command only
|
37
37
|
end
|
38
38
|
|
39
|
-
on_error do |
|
39
|
+
on_error do |_exception|
|
40
40
|
# Error logic here
|
41
41
|
# return false to skip default error handling
|
42
42
|
# binding.pry
|
@@ -125,7 +125,7 @@ module GoodData
|
|
125
125
|
connection_point_set = false
|
126
126
|
question_fmt = 'Select data type of column #%i (%s)'
|
127
127
|
guesser.headers.each_with_index do |header, i|
|
128
|
-
options = guess[header].map
|
128
|
+
options = guess[header].map(&:to_s)
|
129
129
|
options = options.select { |t| t != :connection_point.to_s } if connection_point_set
|
130
130
|
type = ask question_fmt % [i + 1, header], :answers => options
|
131
131
|
model.push :title => header, :name => header, :type => type.upcase
|
@@ -108,7 +108,7 @@ module GoodData
|
|
108
108
|
def jack_in(options)
|
109
109
|
goodfile_path = GoodData::Helpers.find_goodfile(Pathname('.'))
|
110
110
|
|
111
|
-
spin_session = proc do |goodfile,
|
111
|
+
spin_session = proc do |goodfile, _blueprint|
|
112
112
|
project_id = options[:project_id] || goodfile[:project_id]
|
113
113
|
message = 'You have to provide "project_id". You can either provide it through -p flag'\
|
114
114
|
'or even better way is to fill it in in your Goodfile under key "project_id".'\
|
@@ -125,7 +125,7 @@ module GoodData
|
|
125
125
|
|
126
126
|
puts "Use 'exit' to quit the live session. Use 'q' to jump out of displaying a large output."
|
127
127
|
binding.pry(:quiet => true,
|
128
|
-
:prompt => [proc do |
|
128
|
+
:prompt => [proc do |_target_self, _nest_level, _pry|
|
129
129
|
'project_live_sesion: '
|
130
130
|
end])
|
131
131
|
end
|
@@ -6,7 +6,7 @@ module GoodData
|
|
6
6
|
module Command
|
7
7
|
class Role
|
8
8
|
class << self
|
9
|
-
def list(
|
9
|
+
def list(_pid, opts = { :client => GoodData.connection, :project => GoodData.project })
|
10
10
|
p = opts[:project]
|
11
11
|
fail ArgumentError, 'No :project specified' if p.nil?
|
12
12
|
|
@@ -13,8 +13,8 @@ module GoodData
|
|
13
13
|
|
14
14
|
params = options[:expanded_params] || {}
|
15
15
|
|
16
|
-
GoodData.
|
17
|
-
sst =
|
16
|
+
client = GoodData.connect(options[:username], options[:password])
|
17
|
+
sst = client.connection.sst_token
|
18
18
|
pwd = Pathname.new(Dir.pwd)
|
19
19
|
|
20
20
|
server_uri = URI(options[:server]) unless options[:server].nil?
|
data/lib/gooddata/connection.rb
CHANGED
data/lib/gooddata/core/rest.rb
CHANGED
@@ -67,25 +67,29 @@ module GoodData
|
|
67
67
|
def upload_to_user_webdav(file, options = {})
|
68
68
|
u = URI(GoodData.project.links['uploads'])
|
69
69
|
url = URI.join(u.to_s.chomp(u.path.to_s), '/uploads/')
|
70
|
+
|
70
71
|
connection.upload(file, options.merge(
|
71
|
-
:directory => options[:directory],
|
72
72
|
:staging_url => url
|
73
73
|
))
|
74
74
|
end
|
75
75
|
|
76
|
-
def get_project_webdav_path(
|
76
|
+
def get_project_webdav_path(_file, _options = {})
|
77
77
|
u = URI(GoodData.project.links['uploads'])
|
78
78
|
URI.join(u.to_s.chomp(u.path.to_s), '/project-uploads/', "#{GoodData.project.pid}/")
|
79
79
|
end
|
80
80
|
|
81
81
|
def upload_to_project_webdav(file, options = {})
|
82
|
+
webdav_filename = File.basename(file)
|
83
|
+
url = get_project_webdav_path(webdav_filename, options)
|
84
|
+
connection.upload(file, options.merge(:staging_url => url))
|
85
|
+
end
|
86
|
+
|
87
|
+
def download_from_project_webdav(file, where, options = {})
|
82
88
|
url = get_project_webdav_path(file, options)
|
83
|
-
connection.
|
84
|
-
:directory => options[:directory],
|
85
|
-
:staging_url => url))
|
89
|
+
connection.download(file, where, options.merge(:staging_url => url))
|
86
90
|
end
|
87
91
|
|
88
|
-
def get_user_webdav_path(
|
92
|
+
def get_user_webdav_path(_file, _options = {})
|
89
93
|
u = URI(GoodData.project.links['uploads'])
|
90
94
|
URI.join(u.to_s.chomp(u.path.to_s), '/uploads/')
|
91
95
|
end
|
@@ -110,7 +114,7 @@ module GoodData
|
|
110
114
|
response = GoodData.get(link, :process => false)
|
111
115
|
while response.code == code
|
112
116
|
sleep sleep_interval
|
113
|
-
GoodData.
|
117
|
+
GoodData::Rest::Client.retryable(:tries => 3, :on => RestClient::InternalServerError) do
|
114
118
|
sleep sleep_interval
|
115
119
|
response = GoodData.get(link, :process => false)
|
116
120
|
end
|
@@ -139,7 +143,7 @@ module GoodData
|
|
139
143
|
response = get(link)
|
140
144
|
while bl.call(response)
|
141
145
|
sleep sleep_interval
|
142
|
-
|
146
|
+
GoodData::Rest::Client.retryable(:tries => 3, :on => RestClient::InternalServerError) do
|
143
147
|
sleep sleep_interval
|
144
148
|
response = get(link)
|
145
149
|
end
|
@@ -1,6 +1,11 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
+
require 'hashie'
|
3
|
+
|
4
|
+
require 'hashie/extensions/deep_merge'
|
2
5
|
|
3
6
|
class Hash
|
7
|
+
include Hashie::Extensions::DeepMerge
|
8
|
+
|
4
9
|
# Return a hash that includes everything but the given keys. This is useful for
|
5
10
|
# limiting a set of parameters to everything but a few known toggles:
|
6
11
|
#
|
@@ -22,4 +27,19 @@ class Hash
|
|
22
27
|
keys.each { |key| delete(key) }
|
23
28
|
self
|
24
29
|
end
|
30
|
+
|
31
|
+
def undot
|
32
|
+
# for each key-value config given
|
33
|
+
hashes = map do |k, v|
|
34
|
+
# dot notation to hash
|
35
|
+
k.split('__').reverse.reduce(v) do |memo, obj|
|
36
|
+
{ obj => memo }.extend(Hashie::Extensions::DeepMerge)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# merge back the keys as they came
|
41
|
+
hashes.reduce do |memo, obj|
|
42
|
+
memo.deep_merge(obj)
|
43
|
+
end
|
44
|
+
end
|
25
45
|
end
|
@@ -38,7 +38,7 @@ module GoodData
|
|
38
38
|
# @option opts [String] :path File to write data to
|
39
39
|
# @option opts [Array] :data Mandatory array of data to write
|
40
40
|
# @option opts [String] :header Optional Header row
|
41
|
-
def write(opts, &
|
41
|
+
def write(opts, &_block)
|
42
42
|
path = opts[:path]
|
43
43
|
header = opts[:header]
|
44
44
|
data = opts[:data]
|
@@ -18,6 +18,57 @@ module GoodData
|
|
18
18
|
RUBY_PLATFORM =~ /-darwin\d/
|
19
19
|
end
|
20
20
|
|
21
|
+
ENCODED_PARAMS_KEY = :gd_encoded_params
|
22
|
+
ENCODED_HIDDEN_PARAMS_KEY = :gd_encoded_hidden_params
|
23
|
+
|
24
|
+
# Encodes parameters for passing them to GD execution platform.
|
25
|
+
# Core types are kept and complex types (arrays, structures, etc) are JSON encoded into key hash "gd_encoded_params" or "gd_encoded_hidden_params", depending on the 'hidden' method param.
|
26
|
+
# The two different keys are used because the params and hidden params are merged by the platform and if we use the same key, the param would be overwritten.
|
27
|
+
#
|
28
|
+
# Core types are following:
|
29
|
+
# - Boolean (true, false)
|
30
|
+
# - Fixnum
|
31
|
+
# - Float
|
32
|
+
# - Nil
|
33
|
+
# - String
|
34
|
+
#
|
35
|
+
# @param [Hash] params Parameters to be encoded
|
36
|
+
# @return [Hash] Encoded parameters
|
37
|
+
def encode_params(params, hidden = false)
|
38
|
+
res = {}
|
39
|
+
nested = {}
|
40
|
+
core_types = [FalseClass, Fixnum, Float, NilClass, TrueClass, String]
|
41
|
+
params.each do |k, v|
|
42
|
+
if core_types.include?(v.class)
|
43
|
+
res[k] = v
|
44
|
+
else
|
45
|
+
nested[k] = v
|
46
|
+
end
|
47
|
+
end
|
48
|
+
key = hidden ? ENCODED_PARAMS_KEY : ENCODED_HIDDEN_PARAMS_KEY
|
49
|
+
res[key] = nested.to_json unless nested.empty?
|
50
|
+
res
|
51
|
+
end
|
52
|
+
|
53
|
+
# Decodes params as they came from the platform
|
54
|
+
# The "data" key is supposed to be json and it's parsed - if this
|
55
|
+
def decode_params(params)
|
56
|
+
key = ENCODED_PARAMS_KEY.to_s
|
57
|
+
hidden_key = ENCODED_HIDDEN_PARAMS_KEY.to_s
|
58
|
+
data_params = params[key] || '{}'
|
59
|
+
hidden_data_params = params[hidden_key] || '{}'
|
60
|
+
|
61
|
+
begin
|
62
|
+
parsed_data_params = JSON.parse(data_params)
|
63
|
+
parsed_hidden_data_params = JSON.parse(hidden_data_params)
|
64
|
+
rescue JSON::ParserError => e
|
65
|
+
raise e.class, "Error reading json from '#{key}' or '#{hidden_key}' in params #{params}\n #{e.message}"
|
66
|
+
end
|
67
|
+
params.delete(key)
|
68
|
+
params.delete(hidden_key)
|
69
|
+
params.merge(parsed_data_params).merge(parsed_hidden_data_params)
|
70
|
+
end
|
71
|
+
|
21
72
|
def error(msg)
|
22
73
|
STDERR.puts(msg)
|
23
74
|
exit 1
|
@@ -36,8 +87,15 @@ module GoodData
|
|
36
87
|
nil
|
37
88
|
end
|
38
89
|
|
90
|
+
def get_path(an_object, path = [])
|
91
|
+
return an_object if path.empty?
|
92
|
+
path.reduce(an_object) do |a, e|
|
93
|
+
a && a.key?(e) ? a[e] : nil
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
39
97
|
def hash_dfs(thing, &block)
|
40
|
-
if !thing.is_a?(Hash) && !thing.is_a?(Array)
|
98
|
+
if !thing.is_a?(Hash) && !thing.is_a?(Array) # rubocop:disable Style/GuardClause
|
41
99
|
elsif thing.is_a?(Array)
|
42
100
|
thing.each do |child|
|
43
101
|
hash_dfs(child, &block)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module GoodData
|
4
|
+
module Mixin
|
5
|
+
module Lockable
|
6
|
+
# Locks an object. Locked object cannot be changed by certain users.
|
7
|
+
#
|
8
|
+
# @return [GoodData::Mixin::Lockable]
|
9
|
+
def lock
|
10
|
+
meta['locked'] = 1
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
# Sames as #lock. Locks an object and immediately saves it.
|
15
|
+
#
|
16
|
+
# @return [GoodData::Mixin::Lockable]
|
17
|
+
def lock!
|
18
|
+
lock
|
19
|
+
save
|
20
|
+
end
|
21
|
+
|
22
|
+
# Unlocks an object.
|
23
|
+
#
|
24
|
+
# @return [GoodData::Mixin::Lockable]
|
25
|
+
def unlock
|
26
|
+
meta.delete('locked')
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# Same as #unlock. Unlocks an object and immediately saves it
|
31
|
+
#
|
32
|
+
# @return [GoodData::Mixin::Lockable]
|
33
|
+
def unlock!
|
34
|
+
unlock
|
35
|
+
save
|
36
|
+
end
|
37
|
+
|
38
|
+
# Locks an object with all used objects. The types of objects that are affected by locks
|
39
|
+
# are dashboards, reports and metrics. This means that if you lock a dashboard by this method
|
40
|
+
# all used reports and metrics are also locked. If you lock a report all used metrics are also
|
41
|
+
# locked. The current object is reloaded. This means that the #locked? will return true.
|
42
|
+
#
|
43
|
+
# @return [GoodData::Mixin::Lockable]
|
44
|
+
def lock_with_dependencies!
|
45
|
+
client.post("/gdc/internal/projects/#{project.pid}/objects/setPermissions",
|
46
|
+
permissions: {
|
47
|
+
lock: true,
|
48
|
+
items: [uri]
|
49
|
+
})
|
50
|
+
reload!
|
51
|
+
end
|
52
|
+
|
53
|
+
# Unlocks an object with all used objects. The types of objects that are affected by locks
|
54
|
+
# are dashboards, reports and metrics. This means that if you unlock a dashboard by this method
|
55
|
+
# all used reports and metrics are also unlocked. If you unlock a report all used metrics are also
|
56
|
+
# unlocked. The current object is unlocked as well. Beware that certain objects might be in use in
|
57
|
+
# multiple contexts. For example one metric can be used in several reports. This method performs no
|
58
|
+
# checks to determine if an object should stay locked or not.
|
59
|
+
#
|
60
|
+
# @return [GoodData::Mixin::Lockable]
|
61
|
+
def unlock_with_dependencies!
|
62
|
+
using('report').pmap { |link| project.reports(link['link']) }.select(&:locked?).pmap(&:unlock!)
|
63
|
+
using('metric').pmap { |link| project.metrics(link['link']) }.select(&:locked?).pmap(&:unlock!)
|
64
|
+
using('projectDashboard').pmap { |link| project.dashboards(link['link']) }.select(&:locked?).pmap(&:unlock!)
|
65
|
+
unlock!
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns true if an object is locked. False otherwise.
|
69
|
+
#
|
70
|
+
# @return [Boolean]
|
71
|
+
def locked?
|
72
|
+
meta['locked'] == 1
|
73
|
+
end
|
74
|
+
|
75
|
+
# Returns true if an object is unlocked. False otherwise.
|
76
|
+
#
|
77
|
+
# @return [Boolean]
|
78
|
+
def unlocked?
|
79
|
+
!locked?
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -35,7 +35,7 @@ module GoodData
|
|
35
35
|
fail 'Unexpected object id format: expected numeric ID, identifier with no slashes or an URI starting with a slash'
|
36
36
|
end
|
37
37
|
# new(GoodData.get uri) unless uri.nil?
|
38
|
-
if uri
|
38
|
+
if uri # rubocop:disable Style/GuardClause
|
39
39
|
raw = client.get(uri)
|
40
40
|
client.create(self, raw, client: client, project: project)
|
41
41
|
end
|
@@ -8,7 +8,7 @@ module GoodData
|
|
8
8
|
# @param options [Hash] the options hash
|
9
9
|
# @option options [Boolean] :full if passed true the subclass can decide to pull in full objects. This is desirable from the usability POV but unfortunately has negative impact on performance so it is not the default
|
10
10
|
# @return [Array<GoodData::MdObject> | Array<Hash>] Return the appropriate metadata objects or their representation
|
11
|
-
def all(
|
11
|
+
def all(_options = { :client => GoodData.connection, :project => GoodData.project })
|
12
12
|
fail NotImplementedError, 'Method should be implemented in subclass. Currently there is no way how to get all metadata objects on API.'
|
13
13
|
end
|
14
14
|
|
@@ -14,12 +14,6 @@ module GoodData
|
|
14
14
|
|
15
15
|
# Returns which objects uses this MD resource
|
16
16
|
def usedby(key = nil, opts = { :client => client, :project => project })
|
17
|
-
p = opts[:project]
|
18
|
-
fail ArgumentError, 'No :project specified' if p.nil?
|
19
|
-
|
20
|
-
project = GoodData::Project[p, opts]
|
21
|
-
fail ArgumentError, 'Wrong :project specified' if project.nil?
|
22
|
-
|
23
17
|
dependency("#{project.md['usedby2']}/#{obj_id}", key, opts)
|
24
18
|
end
|
25
19
|
|
@@ -27,9 +21,6 @@ module GoodData
|
|
27
21
|
|
28
22
|
# Returns which objects this MD resource uses
|
29
23
|
def using(key = nil, opts = { :client => client, :project => project })
|
30
|
-
project = opts[:project]
|
31
|
-
fail ArgumentError, 'Wrong :project specified' if project.nil?
|
32
|
-
|
33
24
|
dependency("#{project.md['using2']}/#{obj_id}", key, opts)
|
34
25
|
end
|
35
26
|
|
@@ -43,9 +43,9 @@ module GoodData
|
|
43
43
|
# Optional authentication modes
|
44
44
|
tmp = opts[:authentication_modes]
|
45
45
|
if tmp
|
46
|
-
if tmp.
|
46
|
+
if tmp.is_a? Array
|
47
47
|
data[:authenticationModes] = tmp
|
48
|
-
elsif tmp.
|
48
|
+
elsif tmp.is_a? String
|
49
49
|
data[:authenticationModes] = [tmp]
|
50
50
|
end
|
51
51
|
end
|