gooddata 0.6.0 → 0.6.2
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.
- checksums.yaml +13 -5
- data/.rubocop.yml +23 -0
- data/.travis.yml +9 -4
- data/CLI.md +439 -0
- data/Gemfile +0 -1
- data/README.md +2 -2
- data/Rakefile +60 -8
- data/doc/templates/default/module/setup.rb +1 -1
- data/examples.rb +2 -0
- data/gooddata +2 -0
- data/gooddata.gemspec +12 -8
- data/lib/gooddata.rb +0 -2
- data/lib/gooddata/bricks/base_downloader.rb +52 -47
- data/lib/gooddata/bricks/brick.rb +20 -31
- data/lib/gooddata/bricks/bricks.rb +1 -1
- data/lib/gooddata/bricks/middleware/base_middleware.rb +9 -7
- data/lib/gooddata/bricks/middleware/bench_middleware.rb +12 -10
- data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +28 -28
- data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +20 -16
- data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +21 -19
- data/lib/gooddata/bricks/middleware/logger_middleware.rb +10 -8
- data/lib/gooddata/bricks/middleware/restforce_middleware.rb +36 -34
- data/lib/gooddata/bricks/middleware/stdout_middleware.rb +11 -9
- data/lib/gooddata/bricks/middleware/twitter_middleware.rb +14 -12
- data/lib/gooddata/bricks/pipeline.rb +28 -0
- data/lib/gooddata/bricks/utils.rb +10 -8
- data/lib/gooddata/cli/cli.rb +1 -6
- data/lib/gooddata/cli/commands/auth_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/console_cmd.rb +7 -5
- data/lib/gooddata/cli/commands/domain_cmd.rb +45 -0
- data/lib/gooddata/cli/commands/process_cmd.rb +42 -5
- data/lib/gooddata/cli/commands/project_cmd.rb +96 -36
- data/lib/gooddata/cli/commands/projects_cmd.rb +21 -0
- data/lib/gooddata/cli/commands/role_cmd.rb +28 -0
- data/lib/gooddata/cli/commands/run_ruby_cmd.rb +5 -5
- data/lib/gooddata/cli/commands/scaffold_cmd.rb +1 -1
- data/lib/gooddata/cli/commands/{profile_cmd.rb → user_cmd.rb} +7 -9
- data/lib/gooddata/cli/shared.rb +3 -2
- data/lib/gooddata/client.rb +16 -304
- data/lib/gooddata/commands/api.rb +13 -5
- data/lib/gooddata/commands/auth.rb +47 -40
- data/lib/gooddata/commands/base.rb +4 -2
- data/lib/gooddata/commands/commands.rb +1 -1
- data/lib/gooddata/commands/datasets.rb +20 -7
- data/lib/gooddata/commands/domain.rb +23 -0
- data/lib/gooddata/commands/process.rb +23 -117
- data/lib/gooddata/commands/project.rb +147 -0
- data/lib/gooddata/commands/projects.rb +8 -102
- data/lib/gooddata/commands/role.rb +26 -0
- data/lib/gooddata/commands/runners.rb +41 -38
- data/lib/gooddata/commands/scaffold.rb +46 -43
- data/lib/gooddata/commands/user.rb +33 -0
- data/lib/gooddata/connection.rb +43 -353
- data/lib/gooddata/core/connection.rb +389 -0
- data/lib/gooddata/core/core.rb +5 -4
- data/lib/gooddata/core/logging.rb +48 -0
- data/lib/gooddata/core/nil_logger.rb +13 -0
- data/lib/gooddata/core/project.rb +70 -0
- data/lib/gooddata/core/rest.rb +120 -0
- data/lib/gooddata/core/threaded.rb +14 -0
- data/lib/gooddata/core/user.rb +19 -0
- data/lib/gooddata/data/data.rb +2 -1
- data/lib/gooddata/data/guesser.rb +16 -12
- data/lib/gooddata/exceptions/command_failed.rb +1 -1
- data/lib/gooddata/exceptions/exceptions.rb +2 -1
- data/lib/gooddata/exceptions/no_project_error.rb +11 -0
- data/lib/gooddata/exceptions/project_not_found.rb +1 -1
- data/lib/gooddata/extensions/big_decimal.rb +6 -2
- data/lib/gooddata/extract.rb +10 -8
- data/lib/gooddata/goodzilla/goodzilla.rb +61 -59
- data/lib/gooddata/helpers.rb +15 -9
- data/lib/gooddata/models/account_settings.rb +124 -0
- data/lib/gooddata/models/attributes/anchor.rb +37 -0
- data/lib/gooddata/models/attributes/attributes.rb +8 -0
- data/lib/gooddata/models/attributes/date_attribute.rb +25 -0
- data/lib/gooddata/models/attributes/time_attribute.rb +24 -0
- data/lib/gooddata/models/columns/attribute.rb +71 -0
- data/lib/gooddata/models/columns/columns.rb +8 -0
- data/lib/gooddata/models/columns/date_column.rb +63 -0
- data/lib/gooddata/models/columns/fact_model.rb +54 -0
- data/lib/gooddata/models/columns/label.rb +55 -0
- data/lib/gooddata/models/columns/reference.rb +57 -0
- data/lib/gooddata/models/dashboard_builder.rb +26 -0
- data/lib/gooddata/models/data_result.rb +10 -9
- data/lib/gooddata/models/domain.rb +131 -0
- data/lib/gooddata/models/empty_result.rb +5 -8
- data/lib/gooddata/models/facts/facts.rb +8 -0
- data/lib/gooddata/models/facts/time_fact.rb +20 -0
- data/lib/gooddata/models/folders/attribute_folder.rb +20 -0
- data/lib/gooddata/models/folders/fact_folder.rb +20 -0
- data/lib/gooddata/models/folders/folders.rb +8 -0
- data/lib/gooddata/models/invitation.rb +78 -0
- data/lib/gooddata/models/links.rb +6 -6
- data/lib/gooddata/models/md_object.rb +25 -0
- data/lib/gooddata/models/metadata.rb +160 -62
- data/lib/gooddata/models/metadata/attribute.rb +81 -0
- data/lib/gooddata/models/metadata/column.rb +61 -0
- data/lib/gooddata/models/{dashboard.rb → metadata/dashboard.rb} +12 -7
- data/lib/gooddata/models/{data_set.rb → metadata/data_set.rb} +5 -4
- data/lib/gooddata/models/metadata/date_dimension.rb +26 -0
- data/lib/gooddata/models/metadata/display_form.rb +61 -0
- data/lib/gooddata/models/metadata/fact.rb +36 -0
- data/lib/gooddata/models/metadata/folder.rb +24 -0
- data/lib/gooddata/models/metadata/metadata.rb +8 -0
- data/lib/gooddata/models/metadata/metric.rb +197 -0
- data/lib/gooddata/models/metadata/report.rb +115 -0
- data/lib/gooddata/models/{report_definition.rb → metadata/report_definition.rb} +16 -10
- data/lib/gooddata/models/metadata/schema.rb +227 -0
- data/lib/gooddata/models/model.rb +38 -1339
- data/lib/gooddata/models/models.rb +5 -2
- data/lib/gooddata/models/module_constants.rb +29 -0
- data/lib/gooddata/models/process.rb +142 -13
- data/lib/gooddata/models/profile.rb +4 -6
- data/lib/gooddata/models/project.rb +406 -136
- data/lib/gooddata/models/project_blueprint.rb +221 -0
- data/lib/gooddata/models/project_builder.rb +136 -0
- data/lib/gooddata/models/project_creator.rb +138 -0
- data/lib/gooddata/models/project_metadata.rb +11 -10
- data/lib/gooddata/models/project_role.rb +92 -0
- data/lib/gooddata/models/references/date_reference.rb +44 -0
- data/lib/gooddata/models/references/references.rb +8 -0
- data/lib/gooddata/models/references/time_reference.rb +13 -0
- data/lib/gooddata/models/report_data_result.rb +11 -11
- data/lib/gooddata/models/schedule.rb +284 -0
- data/lib/gooddata/models/schema_blueprint.rb +158 -0
- data/lib/gooddata/models/schema_builder.rb +81 -0
- data/lib/gooddata/models/tab_builder.rb +23 -0
- data/lib/gooddata/models/user.rb +165 -0
- data/lib/gooddata/version.rb +1 -1
- data/lib/templates/project/data/devs.csv +1 -1
- data/lib/templates/project/data/repos.csv +1 -1
- data/lib/templates/project/model/model.rb.erb +7 -11
- data/spec/bricks/bricks_spec.rb +2 -0
- data/spec/data/test-ci-data.csv +2 -0
- data/spec/data/test_project_model_spec.json +7 -27
- data/spec/helpers/blueprint_helper.rb +2 -0
- data/spec/helpers/cli_helper.rb +2 -0
- data/spec/helpers/connection_helper.rb +14 -1
- data/spec/helpers/project_helper.rb +16 -0
- data/spec/helpers/schema_helper.rb +16 -0
- data/spec/integration/command_projects_spec.rb +7 -7
- data/spec/integration/create_from_template_spec.rb +2 -2
- data/spec/integration/full_project_spec.rb +160 -7
- data/spec/integration/partial_md_export_import_spec.rb +3 -3
- data/spec/logging_in_logging_out_spec.rb +2 -1
- data/spec/spec_helper.rb +26 -4
- data/spec/unit/bricks/bricks_spec.rb +15 -7
- data/spec/unit/bricks/middleware/bench_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/bulk_salesforce_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/gooddata_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/logger_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/restforce_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/stdout_middleware_spec.rb +2 -0
- data/spec/unit/bricks/middleware/twitter_middleware_spec.rb +2 -0
- data/spec/unit/cli/cli_spec.rb +2 -0
- data/spec/unit/cli/commands/cmd_api_spec.rb +23 -15
- data/spec/unit/cli/commands/cmd_auth_spec.rb +8 -4
- data/spec/unit/cli/commands/cmd_domain_spec.rb +82 -0
- data/spec/unit/cli/commands/cmd_process_spec.rb +29 -13
- data/spec/unit/cli/commands/cmd_project_spec.rb +51 -30
- data/spec/unit/cli/commands/cmd_role_spec.rb +44 -0
- data/spec/unit/cli/commands/cmd_run_ruby_spec.rb +8 -4
- data/spec/unit/cli/commands/cmd_scaffold_spec.rb +48 -11
- data/spec/unit/cli/commands/cmd_user_spec.rb +29 -0
- data/spec/unit/commands/command_api_spec.rb +1 -1
- data/spec/unit/commands/command_auth_spec.rb +100 -18
- data/spec/unit/commands/command_dataset_spec.rb +4 -0
- data/spec/unit/commands/command_process_spec.rb +9 -4
- data/spec/unit/commands/command_projects_spec.rb +10 -6
- data/spec/unit/commands/command_scaffold_spec.rb +5 -1
- data/spec/unit/commands/command_user_spec.rb +22 -0
- data/spec/unit/core/connection_spec.rb +35 -6
- data/spec/unit/core/logging_spec.rb +65 -0
- data/spec/unit/core/nil_logger_spec.rb +9 -0
- data/spec/unit/core/project_spec.rb +51 -0
- data/spec/unit/core/rest_spec.rb +33 -0
- data/spec/unit/data/guesser_spec.rb +5 -0
- data/spec/unit/godzilla/goodzilla_spec.rb +2 -0
- data/spec/unit/models/account_settings_spec.rb +28 -0
- data/spec/unit/models/anchor_spec.rb +32 -0
- data/spec/unit/models/attribute_column_spec.rb +7 -0
- data/spec/unit/models/domain_spec.rb +45 -0
- data/spec/unit/models/invitation_spec.rb +13 -0
- data/spec/unit/models/md_object_spec.rb +47 -0
- data/spec/unit/models/metric.rb +92 -0
- data/spec/unit/{model → models}/model_spec.rb +9 -7
- data/spec/unit/models/project_blueprint_spec.rb +202 -0
- data/spec/unit/models/project_creator.rb +73 -0
- data/spec/unit/models/project_role_spec.rb +90 -0
- data/spec/unit/models/project_spec.rb +143 -0
- data/spec/unit/models/schedule_spec.rb +491 -0
- data/spec/unit/{model → models}/schema_builder_spec.rb +2 -0
- data/spec/unit/{model → models}/tools_spec.rb +13 -7
- data/spec/unit/models/user_spec.rb +16 -0
- data/test/test_upload.rb +2 -0
- metadata +189 -86
- data/lib/gooddata/commands/profile.rb +0 -11
- data/lib/gooddata/models/attribute.rb +0 -29
- data/lib/gooddata/models/display_form.rb +0 -9
- data/lib/gooddata/models/fact.rb +0 -19
- data/lib/gooddata/models/metric.rb +0 -99
- data/lib/gooddata/models/report.rb +0 -89
- data/spec/data/blueprint_valid.json +0 -37
- data/spec/unit/cli/commands/cmd_profile_spec.rb +0 -16
- data/spec/unit/commands/command_profile_spec.rb +0 -18
- data/spec/unit/core/core_spec.rb +0 -7
- data/spec/unit/model/blueprint_spec.rb +0 -132
- data/spec/unit/model/project_blueprint_spec.rb +0 -44
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
module GoodData
|
|
4
|
+
module Model
|
|
5
|
+
# GoodData REST API categories
|
|
6
|
+
LDM_CTG = 'ldm'
|
|
7
|
+
LDM_MANAGE_CTG = 'ldm-manage2'
|
|
8
|
+
|
|
9
|
+
# Model naming conventions
|
|
10
|
+
FIELD_PK = 'id'
|
|
11
|
+
FK_SUFFIX = '_id'
|
|
12
|
+
FACT_COLUMN_PREFIX = 'f_'
|
|
13
|
+
DATE_COLUMN_PREFIX = 'dt_'
|
|
14
|
+
TIME_COLUMN_PREFIX = 'tm_'
|
|
15
|
+
LABEL_COLUMN_PREFIX = 'nm_'
|
|
16
|
+
ATTRIBUTE_FOLDER_PREFIX = 'dim'
|
|
17
|
+
ATTRIBUTE_PREFIX = 'attr'
|
|
18
|
+
LABEL_PREFIX = 'label'
|
|
19
|
+
FACT_PREFIX = 'fact'
|
|
20
|
+
DATE_FACT_PREFIX = 'dt'
|
|
21
|
+
DATE_ATTRIBUTE = 'date'
|
|
22
|
+
DATE_ATTRIBUTE_DEFAULT_DISPLAY_FORM = 'mdyy'
|
|
23
|
+
TIME_FACT_PREFIX = 'tm.dt'
|
|
24
|
+
TIME_ATTRIBUTE_PREFIX = 'attr.time'
|
|
25
|
+
FACT_FOLDER_PREFIX = 'ffld'
|
|
26
|
+
|
|
27
|
+
SKIP_FIELD = false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -4,49 +4,178 @@ require 'pry'
|
|
|
4
4
|
|
|
5
5
|
module GoodData
|
|
6
6
|
class Process
|
|
7
|
+
attr_reader :data
|
|
8
|
+
|
|
7
9
|
class << self
|
|
8
|
-
def [](id)
|
|
10
|
+
def [](id, options = {})
|
|
9
11
|
if id == :all
|
|
10
12
|
uri = "/gdc/projects/#{GoodData.project.pid}/dataload/processes"
|
|
11
|
-
GoodData.get(uri)
|
|
13
|
+
data = GoodData.get(uri)
|
|
14
|
+
data['processes']['items'].map do |process_data|
|
|
15
|
+
Process.new(process_data)
|
|
16
|
+
end
|
|
12
17
|
else
|
|
13
18
|
uri = "/gdc/projects/#{GoodData.project.pid}/dataload/processes/#{id}"
|
|
14
|
-
|
|
19
|
+
new(GoodData.get(uri))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def all
|
|
24
|
+
Process[:all]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# TODO: Check the params.
|
|
28
|
+
def with_deploy(dir, options = {}, &block)
|
|
29
|
+
# verbose = options[:verbose] || false
|
|
30
|
+
GoodData.with_project(options[:project_id]) do |project|
|
|
31
|
+
params = options[:params].nil? ? [] : [options[:params]]
|
|
32
|
+
if block
|
|
33
|
+
begin
|
|
34
|
+
res = GoodData::Process.deploy(dir, options.merge(:files_to_exclude => params))
|
|
35
|
+
block.call(res)
|
|
36
|
+
ensure
|
|
37
|
+
res.delete if res
|
|
38
|
+
end
|
|
39
|
+
else
|
|
40
|
+
GoodData::Process.deploy(dir, options.merge(:files_to_exclude => params))
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def upload_package(dir, files_to_exclude)
|
|
46
|
+
Tempfile.open('deploy-graph-archive') do |temp|
|
|
47
|
+
Zip::OutputStream.open(temp.path) do |zio|
|
|
48
|
+
FileUtils.cd(dir) do
|
|
49
|
+
|
|
50
|
+
files_to_pack = Dir.glob('./**/*').reject { |f| files_to_exclude.include?(Pathname(dir) + f) }
|
|
51
|
+
files_to_pack.each do |item|
|
|
52
|
+
# puts "including #{item}" if verbose
|
|
53
|
+
unless File.directory?(item)
|
|
54
|
+
zio.put_next_entry(item)
|
|
55
|
+
zio.print IO.read(item)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
GoodData.upload_to_user_webdav(temp.path)
|
|
61
|
+
temp
|
|
15
62
|
end
|
|
16
63
|
end
|
|
64
|
+
|
|
65
|
+
def deploy(dir, options = {})
|
|
66
|
+
dir = Pathname(dir) || fail('Directory is not specified')
|
|
67
|
+
fail "\"#{dir}\" is not a directory" unless dir.directory?
|
|
68
|
+
files_to_exclude = options[:files_to_exclude].map { |p| Pathname(p) }
|
|
69
|
+
process_id = options[:process_id]
|
|
70
|
+
|
|
71
|
+
type = options[:type] || 'GRAPH'
|
|
72
|
+
deploy_name = options[:name]
|
|
73
|
+
verbose = options[:verbose] || false
|
|
74
|
+
puts HighLine.color("Deploying #{dir}", HighLine::BOLD) if verbose
|
|
75
|
+
deployed_path = Process.upload_package(dir, files_to_exclude)
|
|
76
|
+
data = {
|
|
77
|
+
:process => {
|
|
78
|
+
:name => deploy_name,
|
|
79
|
+
:path => "/uploads/#{File.basename(deployed_path.path)}",
|
|
80
|
+
:type => type
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
res = if process_id.nil?
|
|
84
|
+
GoodData.post("/gdc/projects/#{GoodData.project.pid}/dataload/processes", data)
|
|
85
|
+
else
|
|
86
|
+
GoodData.put("/gdc/projects/#{GoodData.project.pid}/dataload/processes/#{process_id}", data)
|
|
87
|
+
end
|
|
88
|
+
process = Process.new(res)
|
|
89
|
+
puts HighLine.color("Deploy DONE #{dir}", HighLine::GREEN) if verbose
|
|
90
|
+
process
|
|
91
|
+
end
|
|
17
92
|
end
|
|
18
93
|
|
|
19
94
|
def initialize(data)
|
|
20
95
|
@data = data
|
|
21
96
|
end
|
|
22
97
|
|
|
98
|
+
def delete
|
|
99
|
+
GoodData.delete(uri)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def deploy(dir, options = {})
|
|
103
|
+
process = Process.upload(dir, options.merge(:process_id => process_id))
|
|
104
|
+
puts HighLine.color("Deploy DONE #{dir}", HighLine::GREEN) if verbose
|
|
105
|
+
process
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def process
|
|
109
|
+
raw_data['process']
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def name
|
|
113
|
+
process['name']
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def type
|
|
117
|
+
process['type'].downcase.to_sym
|
|
118
|
+
end
|
|
119
|
+
|
|
23
120
|
def links
|
|
24
|
-
|
|
121
|
+
process['links']
|
|
25
122
|
end
|
|
26
123
|
|
|
27
124
|
def link
|
|
28
125
|
links['self']
|
|
29
126
|
end
|
|
127
|
+
alias_method :uri, :link
|
|
128
|
+
|
|
129
|
+
def obj_id
|
|
130
|
+
uri.split('/').last
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
alias_method :process_id, :obj_id
|
|
30
134
|
|
|
31
135
|
def executions_link
|
|
32
136
|
links['executions']
|
|
33
137
|
end
|
|
34
138
|
|
|
35
|
-
def
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
139
|
+
def graphs
|
|
140
|
+
process['graphs']
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def executables
|
|
144
|
+
process['executables']
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def schedules
|
|
148
|
+
res = []
|
|
149
|
+
|
|
150
|
+
scheds = GoodData::Schedule[:all]
|
|
151
|
+
scheds['schedules']['items'].each do |item|
|
|
152
|
+
if item['schedule']['params']['PROCESS_ID'] == obj_id
|
|
153
|
+
res << GoodData::Schedule.new(item)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
res
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
alias_method :raw_data, :data
|
|
161
|
+
|
|
162
|
+
def execute(executable, options = {})
|
|
163
|
+
params = options[:params] || {}
|
|
164
|
+
hidden_params = options[:hidden_params] || {}
|
|
165
|
+
result = GoodData.post(executions_link,
|
|
166
|
+
:execution => {
|
|
167
|
+
:graph => executable.to_s,
|
|
168
|
+
:params => params,
|
|
169
|
+
:hiddenParams => hidden_params
|
|
170
|
+
})
|
|
42
171
|
begin
|
|
43
172
|
GoodData.poll(result, 'executionTask')
|
|
44
173
|
rescue RestClient::RequestFailed => e
|
|
45
|
-
|
|
174
|
+
raise(e)
|
|
46
175
|
ensure
|
|
47
176
|
result = GoodData.get(result['executionTask']['links']['detail'])
|
|
48
177
|
if result['executionDetail']['status'] == 'ERROR'
|
|
49
|
-
fail "Runing process failed. You can look at a log here #{result[
|
|
178
|
+
fail "Runing process failed. You can look at a log here #{result["executionDetail"]["logFileName"]}"
|
|
50
179
|
end
|
|
51
180
|
end
|
|
52
181
|
result
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
module GoodData
|
|
4
4
|
class Profile
|
|
5
5
|
private_class_method :new
|
|
6
|
-
attr_reader :user
|
|
6
|
+
attr_reader :user, :json
|
|
7
7
|
|
|
8
8
|
class << self
|
|
9
9
|
def load
|
|
@@ -16,11 +16,9 @@ module GoodData
|
|
|
16
16
|
@json['accountSetting']['links']['projects']
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
@json
|
|
21
|
-
end
|
|
19
|
+
alias_method :to_json, :json
|
|
22
20
|
|
|
23
|
-
def [](key)
|
|
21
|
+
def [](key, options = {})
|
|
24
22
|
@json['accountSetting'][key]
|
|
25
23
|
end
|
|
26
24
|
|
|
@@ -31,4 +29,4 @@ module GoodData
|
|
|
31
29
|
@user = @json['accountSetting']['firstName'] + ' ' + @json['accountSetting']['lastName']
|
|
32
30
|
end
|
|
33
31
|
end
|
|
34
|
-
end
|
|
32
|
+
end
|
|
@@ -3,17 +3,19 @@
|
|
|
3
3
|
require 'zip'
|
|
4
4
|
require 'fileutils'
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
require_relative 'process'
|
|
7
|
+
require_relative '../exceptions/no_project_error'
|
|
8
|
+
require_relative 'project_role'
|
|
9
9
|
|
|
10
|
+
module GoodData
|
|
10
11
|
class Project
|
|
11
12
|
USERSPROJECTS_PATH = '/gdc/account/profile/%s/projects'
|
|
12
13
|
PROJECTS_PATH = '/gdc/projects'
|
|
13
14
|
PROJECT_PATH = '/gdc/projects/%s'
|
|
14
15
|
SLIS_PATH = '/ldm/singleloadinterface'
|
|
16
|
+
DEFAULT_INVITE_MESSAGE = 'Join us!'
|
|
15
17
|
|
|
16
|
-
attr_accessor :connection
|
|
18
|
+
attr_accessor :connection, :json
|
|
17
19
|
|
|
18
20
|
class << self
|
|
19
21
|
# Returns an array of all projects accessible by
|
|
@@ -31,13 +33,13 @@ module GoodData
|
|
|
31
33
|
# - /gdc/projects/<id>
|
|
32
34
|
# - <id>
|
|
33
35
|
#
|
|
34
|
-
def [](id)
|
|
35
|
-
return id if id.respond_to?(:
|
|
36
|
+
def [](id, options = {})
|
|
37
|
+
return id if id.respond_to?(:project?) && id.project?
|
|
36
38
|
if id == :all
|
|
37
39
|
Project.all
|
|
38
40
|
else
|
|
39
|
-
if id.to_s !~
|
|
40
|
-
|
|
41
|
+
if id.to_s !~ %r{^(\/gdc\/(projects|md)\/)?[a-zA-Z\d]+$}
|
|
42
|
+
fail(ArgumentError, 'wrong type of argument. Should be either project ID or path')
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
id = id.match(/[a-zA-Z\d]+$/)[0] if id =~ /\//
|
|
@@ -57,103 +59,45 @@ module GoodData
|
|
|
57
59
|
GoodData.logger.info "Creating project #{attributes[:title]}"
|
|
58
60
|
|
|
59
61
|
auth_token = attributes[:auth_token] || GoodData.connection.auth_token
|
|
60
|
-
fail
|
|
61
|
-
|
|
62
|
-
json = {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
62
|
+
fail 'You have to provide your token for creating projects as :auth_token parameter' if auth_token.nil? || auth_token.empty?
|
|
63
|
+
|
|
64
|
+
json = {
|
|
65
|
+
'project' =>
|
|
66
|
+
{
|
|
67
|
+
'meta' => {
|
|
68
|
+
'title' => attributes[:title],
|
|
69
|
+
'summary' => attributes[:summary] || 'No summary'
|
|
70
|
+
},
|
|
71
|
+
'content' => {
|
|
72
|
+
'guidedNavigation' => attributes[:guided_navigation] || 1,
|
|
73
|
+
'authorizationToken' => auth_token,
|
|
74
|
+
'driver' => attributes[:driver] || 'Pg'
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
json['project']['meta']['projectTemplate'] = attributes[:template] if attributes[:template] && !attributes[:template].empty?
|
|
76
80
|
project = Project.new json
|
|
77
81
|
project.save
|
|
78
82
|
|
|
79
83
|
# until it is enabled or deleted, recur. This should still end if there is a exception thrown out from RESTClient. This sometimes happens from WebApp when request is too long
|
|
80
|
-
while project.state.to_s !=
|
|
81
|
-
if project.state.to_s ==
|
|
84
|
+
while project.state.to_s != 'enabled'
|
|
85
|
+
if project.state.to_s == 'deleted'
|
|
82
86
|
# if project is switched to deleted state, fail. This is usually problem of creating a template which is invalid.
|
|
83
|
-
fail
|
|
87
|
+
fail 'Project was marked as deleted during creation. This usually means you were trying to create from template and it failed.'
|
|
84
88
|
end
|
|
85
89
|
sleep(3)
|
|
86
90
|
project.reload!
|
|
87
91
|
end
|
|
88
92
|
|
|
89
93
|
if block
|
|
90
|
-
GoodData
|
|
94
|
+
GoodData.with_project(project) do |p|
|
|
91
95
|
block.call(p)
|
|
92
96
|
end
|
|
93
97
|
end
|
|
98
|
+
sleep 3
|
|
94
99
|
project
|
|
95
100
|
end
|
|
96
|
-
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
def initialize(json)
|
|
100
|
-
@json = json
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def save
|
|
104
|
-
response = GoodData.post PROJECTS_PATH, raw_data
|
|
105
|
-
if uri == nil
|
|
106
|
-
response = GoodData.get response['uri']
|
|
107
|
-
@json = response
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def saved?
|
|
112
|
-
!!uri
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def reload!
|
|
116
|
-
if saved?
|
|
117
|
-
response = GoodData.get(uri)
|
|
118
|
-
@json = response
|
|
119
|
-
end
|
|
120
|
-
self
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
def delete
|
|
124
|
-
raise "Project '#{title}' with id #{uri} is already deleted" if state == :deleted
|
|
125
|
-
GoodData.delete(uri)
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
def uri
|
|
129
|
-
data['links']['self'] if data && data['links'] && data['links']['self']
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def browser_uri(options={})
|
|
133
|
-
ui = options[:ui]
|
|
134
|
-
if ui
|
|
135
|
-
GoodData.connection.url + '#s=' + uri
|
|
136
|
-
else
|
|
137
|
-
GoodData.connection.url + uri
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
def obj_id
|
|
142
|
-
uri.split('/').last
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
alias :pid :obj_id
|
|
146
|
-
|
|
147
|
-
def title
|
|
148
|
-
data['meta']['title'] if data['meta']
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
def state
|
|
152
|
-
data['content']['state'].downcase.to_sym if data['content'] && data['content']['state']
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def md
|
|
156
|
-
@md ||= Links.new GoodData.get(data['links']['metadata'])
|
|
157
101
|
end
|
|
158
102
|
|
|
159
103
|
# Creates a data set within the project
|
|
@@ -167,44 +111,119 @@ module GoodData
|
|
|
167
111
|
builder = block.call(Model::SchemaBuilder.new(schema_def))
|
|
168
112
|
builder.to_schema
|
|
169
113
|
else
|
|
170
|
-
sch = {:title => schema_def, :columns => columns} if columns
|
|
114
|
+
sch = { :title => schema_def, :columns => columns } if columns
|
|
171
115
|
sch = Model::Schema.new schema_def if schema_def.is_a? Hash
|
|
172
116
|
sch = schema_def if schema_def.is_a?(Model::Schema)
|
|
173
|
-
|
|
117
|
+
fail(ArgumentError, 'Required either schema object or title plus columns array') unless schema_def.is_a? Model::Schema
|
|
174
118
|
sch
|
|
175
119
|
end
|
|
176
120
|
Model.add_schema(schema, self)
|
|
177
121
|
end
|
|
178
122
|
|
|
179
|
-
def add_metric(options={})
|
|
180
|
-
|
|
123
|
+
def add_metric(options = {})
|
|
124
|
+
options[:expression] || fail('Metric has to have its expression defined')
|
|
181
125
|
m1 = GoodData::Metric.create(options)
|
|
182
126
|
m1.save
|
|
183
127
|
end
|
|
184
128
|
|
|
185
|
-
def add_report(options={})
|
|
129
|
+
def add_report(options = {})
|
|
186
130
|
rep = GoodData::Report.create(options)
|
|
187
131
|
rep.save
|
|
188
132
|
end
|
|
189
133
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
134
|
+
# Gets author of project
|
|
135
|
+
#
|
|
136
|
+
# @return [String] Project author
|
|
137
|
+
def author
|
|
138
|
+
# TODO: Return object instead
|
|
139
|
+
@json['project']['meta']['author']
|
|
193
140
|
end
|
|
194
141
|
|
|
142
|
+
# Adds user to project
|
|
143
|
+
#
|
|
144
|
+
# TODO: Discuss with @fluke777 if is not #invite sufficient
|
|
195
145
|
def add_user(email_address, domain)
|
|
196
|
-
|
|
146
|
+
fail 'Not implemented'
|
|
197
147
|
end
|
|
198
148
|
|
|
199
|
-
|
|
200
|
-
|
|
149
|
+
# Returns web interface URI of project
|
|
150
|
+
#
|
|
151
|
+
# @return [String] Project URL
|
|
152
|
+
def browser_uri(options = {})
|
|
153
|
+
grey = options[:grey]
|
|
154
|
+
if grey
|
|
155
|
+
GoodData.connection.url + uri
|
|
156
|
+
else
|
|
157
|
+
GoodData.connection.url + '#s=' + uri
|
|
158
|
+
end
|
|
201
159
|
end
|
|
202
160
|
|
|
203
|
-
|
|
204
|
-
|
|
161
|
+
# Clones project
|
|
162
|
+
#
|
|
163
|
+
# @return [GoodData::Project] Newly created project
|
|
164
|
+
def clone(options = {})
|
|
165
|
+
# TODO: Refactor so if export or import fails the new_project will be cleaned
|
|
166
|
+
with_data = options[:data] || true
|
|
167
|
+
with_users = options[:users] || false
|
|
168
|
+
title = options[:title] || "Clone of #{title}"
|
|
169
|
+
|
|
170
|
+
# Create the project first so we know that it is passing. What most likely is wrong is the tokena and the export actaully takes majoiryt of the time
|
|
171
|
+
new_project = GoodData::Project.create(options.merge(:title => title))
|
|
172
|
+
|
|
173
|
+
export = {
|
|
174
|
+
:exportProject => {
|
|
175
|
+
:exportUsers => with_users ? 1 : 0,
|
|
176
|
+
:exportData => with_data ? 1 : 0
|
|
177
|
+
}
|
|
178
|
+
}
|
|
205
179
|
|
|
206
|
-
|
|
207
|
-
|
|
180
|
+
result = GoodData.post("/gdc/md/#{obj_id}/maintenance/export", export)
|
|
181
|
+
export_token = result['exportArtifact']['token']
|
|
182
|
+
status_url = result['exportArtifact']['status']['uri']
|
|
183
|
+
|
|
184
|
+
state = GoodData.get(status_url)['taskState']['status']
|
|
185
|
+
while state == 'RUNNING'
|
|
186
|
+
sleep 5
|
|
187
|
+
result = GoodData.get(status_url)
|
|
188
|
+
state = result['taskState']['status']
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
import = {
|
|
192
|
+
:importProject => {
|
|
193
|
+
:token => export_token
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
result = GoodData.post("/gdc/md/#{new_project.obj_id}/maintenance/import", import)
|
|
198
|
+
status_url = result['uri']
|
|
199
|
+
state = GoodData.get(status_url)['taskState']['status']
|
|
200
|
+
while state == 'RUNNING'
|
|
201
|
+
sleep 5
|
|
202
|
+
result = GoodData.get(status_url)
|
|
203
|
+
state = result['taskState']['status']
|
|
204
|
+
end
|
|
205
|
+
new_project
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Project contributor
|
|
209
|
+
#
|
|
210
|
+
# @return [String] Project contributor
|
|
211
|
+
# TODO: Return as object
|
|
212
|
+
def contributor
|
|
213
|
+
# TODO: Return object instead
|
|
214
|
+
@json['project']['meta']['contributor']
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Gets the date when created
|
|
218
|
+
#
|
|
219
|
+
# @return [DateTime] Date time when created
|
|
220
|
+
def created
|
|
221
|
+
DateTime.parse(@json['meta']['created'])
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Gets ruby wrapped raw project JSON data
|
|
225
|
+
def data
|
|
226
|
+
raw_data['project']
|
|
208
227
|
end
|
|
209
228
|
|
|
210
229
|
def datasets
|
|
@@ -215,67 +234,318 @@ module GoodData
|
|
|
215
234
|
end
|
|
216
235
|
end
|
|
217
236
|
|
|
218
|
-
|
|
219
|
-
|
|
237
|
+
# Deletes project
|
|
238
|
+
def delete
|
|
239
|
+
fail "Project '#{title}' with id #{uri} is already deleted" if state == :deleted
|
|
240
|
+
GoodData.delete(uri)
|
|
220
241
|
end
|
|
221
242
|
|
|
222
|
-
|
|
223
|
-
|
|
243
|
+
# Deletes dashboards for project
|
|
244
|
+
def delete_dashboards
|
|
245
|
+
Dashboard.all.map { |data| Dashboard[data['link']] }.each { |d| d.delete }
|
|
224
246
|
end
|
|
225
247
|
|
|
248
|
+
# Gets project role by its identifier
|
|
249
|
+
#
|
|
250
|
+
# @param [String] role_name Title of role to look for
|
|
251
|
+
# @return [GoodData::ProjectRole] Project role if found
|
|
252
|
+
def get_role_by_identifier(role_name)
|
|
253
|
+
tmp = roles
|
|
254
|
+
tmp.each do |role|
|
|
255
|
+
return role if role.identifier.downcase == role_name.downcase
|
|
256
|
+
end
|
|
257
|
+
nil
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Gets project role byt its summary
|
|
261
|
+
#
|
|
262
|
+
# @param [String] role_summary Summary of role to look for
|
|
263
|
+
# @return [GoodData::ProjectRole] Project role if found
|
|
264
|
+
def get_role_by_summary(role_summary)
|
|
265
|
+
tmp = roles
|
|
266
|
+
tmp.each do |role|
|
|
267
|
+
return role if role.summary.downcase == role_summary.downcase
|
|
268
|
+
end
|
|
269
|
+
nil
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Gets project role by its name
|
|
273
|
+
#
|
|
274
|
+
# @param [String] role_title Title of role to look for
|
|
275
|
+
# @return [GoodData::ProjectRole] Project role if found
|
|
276
|
+
def get_role_by_title(role_title)
|
|
277
|
+
tmp = roles
|
|
278
|
+
tmp.each do |role|
|
|
279
|
+
return role if role.title.downcase == role_title.downcase
|
|
280
|
+
end
|
|
281
|
+
nil
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Initializes object instance from raw wire JSON
|
|
285
|
+
#
|
|
286
|
+
# @param json Json used for initialization
|
|
287
|
+
def initialize(json)
|
|
288
|
+
@json = json
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Invites new user to project
|
|
292
|
+
#
|
|
293
|
+
# @param email [String] User to be invited
|
|
294
|
+
# @param role [String] Role URL or Role ID to be used
|
|
295
|
+
# @param msg [String] Optional invite message
|
|
296
|
+
#
|
|
297
|
+
# TODO: Return invite object
|
|
298
|
+
def invite(email, role, msg = DEFAULT_INVITE_MESSAGE)
|
|
299
|
+
puts "Inviting #{email}, role: #{role}"
|
|
300
|
+
|
|
301
|
+
role_url = nil
|
|
302
|
+
if role.index('/gdc/') != 0
|
|
303
|
+
tmp = get_role_by_identifier(role)
|
|
304
|
+
tmp = get_role_by_title(role) if tmp.nil?
|
|
305
|
+
role_url = tmp['url'] if tmp
|
|
306
|
+
else
|
|
307
|
+
role_url = role if role_url.nil?
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
data = {
|
|
311
|
+
:invitations => [
|
|
312
|
+
{
|
|
313
|
+
:invitation => {
|
|
314
|
+
:content => {
|
|
315
|
+
:email => email,
|
|
316
|
+
:role => role_url,
|
|
317
|
+
:action => {
|
|
318
|
+
:setMessage => msg
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
url = "/gdc/projects/#{pid}/invitations"
|
|
327
|
+
GoodData.post(url, data)
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Returns invitations to project
|
|
331
|
+
#
|
|
332
|
+
# @return [Array<GoodData::Invitation>] List of invitations
|
|
333
|
+
def invitations
|
|
334
|
+
res = []
|
|
335
|
+
|
|
336
|
+
tmp = GoodData.get @json['project']['links']['invitations']
|
|
337
|
+
tmp['invitations'].each do |invitation|
|
|
338
|
+
res << GoodData::Invitation.new(invitation)
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
res
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
# Returns project related links
|
|
345
|
+
#
|
|
346
|
+
# @return [Hash] Project related links
|
|
226
347
|
def links
|
|
227
348
|
data['links']
|
|
228
349
|
end
|
|
229
350
|
|
|
230
|
-
def
|
|
231
|
-
|
|
351
|
+
def md
|
|
352
|
+
@md ||= Links.new GoodData.get(data['links']['metadata'])
|
|
232
353
|
end
|
|
233
354
|
|
|
234
|
-
|
|
235
|
-
|
|
355
|
+
# Gets raw resource ID
|
|
356
|
+
#
|
|
357
|
+
# @return [String] Raw resource ID
|
|
358
|
+
def obj_id
|
|
359
|
+
uri.split('/').last
|
|
236
360
|
end
|
|
237
361
|
|
|
238
|
-
|
|
362
|
+
alias_method :pid, :obj_id
|
|
363
|
+
|
|
364
|
+
def partial_md_export(objects, options = {})
|
|
239
365
|
# TODO: refactor polling to md_polling in client
|
|
240
366
|
|
|
241
|
-
fail
|
|
367
|
+
fail 'Nothing to migrate. You have to pass list of objects, ids or uris that you would like to migrate' if objects.nil? || objects.empty?
|
|
368
|
+
fail 'The objects to migrate has to be provided as an array' unless objects.is_a?(Array)
|
|
369
|
+
|
|
242
370
|
target_project = options[:project]
|
|
243
|
-
fail
|
|
371
|
+
fail 'You have to provide a project instance or project pid to migrate to' if target_project.nil?
|
|
244
372
|
target_project = GoodData::Project[target_project]
|
|
245
|
-
objects = objects.map {|obj| GoodData::MdObject[obj]}
|
|
246
|
-
GoodData.logging_on
|
|
373
|
+
objects = objects.map { |obj| GoodData::MdObject[obj] }
|
|
247
374
|
export_payload = {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
375
|
+
:partialMDExport => {
|
|
376
|
+
:uris => objects.map { |obj| obj.uri }
|
|
377
|
+
}
|
|
251
378
|
}
|
|
252
379
|
result = GoodData.post("#{GoodData.project.md['maintenance']}/partialmdexport", export_payload)
|
|
253
|
-
polling_url = result[
|
|
254
|
-
token = result[
|
|
380
|
+
polling_url = result['partialMDArtifact']['status']['uri']
|
|
381
|
+
token = result['partialMDArtifact']['token']
|
|
255
382
|
|
|
256
|
-
polling_result = GoodData.
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
end
|
|
260
|
-
fail "Exporting objects failed" if polling_result["wTaskStatus"]["poll"]["status"] == "ERROR"
|
|
383
|
+
polling_result = GoodData.wait_for_polling_result(polling_url)
|
|
384
|
+
|
|
385
|
+
fail 'Exporting objects failed' if polling_result['wTaskStatus']['status'] == 'ERROR'
|
|
261
386
|
|
|
262
387
|
import_payload = {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
388
|
+
:partialMDImport => {
|
|
389
|
+
:token => token,
|
|
390
|
+
:overwriteNewer => '1',
|
|
391
|
+
:updateLDMObjects => '0'
|
|
267
392
|
}
|
|
268
393
|
}
|
|
269
394
|
|
|
270
395
|
result = GoodData.post("#{target_project.md['maintenance']}/partialmdimport", import_payload)
|
|
271
|
-
|
|
272
|
-
polling_result = GoodData.
|
|
273
|
-
|
|
274
|
-
|
|
396
|
+
polling_url = result['uri']
|
|
397
|
+
polling_result = GoodData.wait_for_polling_result(polling_url)
|
|
398
|
+
|
|
399
|
+
fail 'Exporting objects failed' if polling_result['wTaskStatus']['status'] == 'ERROR'
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
alias_method :transfer_objects, :partial_md_export
|
|
403
|
+
|
|
404
|
+
# Checks if this object instance is project
|
|
405
|
+
#
|
|
406
|
+
# @return [Boolean] Return true for all instances
|
|
407
|
+
def project?
|
|
408
|
+
true
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# Forces project to reload
|
|
412
|
+
def reload!
|
|
413
|
+
if saved?
|
|
414
|
+
response = GoodData.get(uri)
|
|
415
|
+
@json = response
|
|
275
416
|
end
|
|
276
|
-
|
|
417
|
+
self
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
# Gets the list or project roles
|
|
421
|
+
#
|
|
422
|
+
# @return [Array<GoodData::ProjectRole>] List of roles
|
|
423
|
+
def roles
|
|
424
|
+
url = "/gdc/projects/#{pid}/roles"
|
|
277
425
|
|
|
426
|
+
res = []
|
|
427
|
+
|
|
428
|
+
tmp = GoodData.get(url)
|
|
429
|
+
tmp['projectRoles']['roles'].each do |role_url|
|
|
430
|
+
json = GoodData.get role_url
|
|
431
|
+
res << GoodData::ProjectRole.new(json)
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
res
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
# Saves project
|
|
438
|
+
def save
|
|
439
|
+
response = GoodData.post PROJECTS_PATH, raw_data
|
|
440
|
+
if uri.nil?
|
|
441
|
+
response = GoodData.get response['uri']
|
|
442
|
+
@json = response
|
|
443
|
+
end
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
# Checks if is project saved
|
|
447
|
+
#
|
|
448
|
+
# @return [Boolean] True if saved, false if not
|
|
449
|
+
def saved?
|
|
450
|
+
res = uri.nil?
|
|
451
|
+
!res
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Gets project schedules
|
|
455
|
+
#
|
|
456
|
+
# @return [Array<GoodData::Schedule>] List of schedules
|
|
457
|
+
def schedules
|
|
458
|
+
res = []
|
|
459
|
+
tmp = GoodData.get @json['project']['links']['schedules']
|
|
460
|
+
tmp['schedules']['items'].each do |schedule|
|
|
461
|
+
res << GoodData::Schedule.new(schedule)
|
|
462
|
+
end
|
|
463
|
+
res
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# Gets SLIs data
|
|
467
|
+
#
|
|
468
|
+
# @return [GoodData::Metadata] SLI Metadata
|
|
469
|
+
def slis
|
|
470
|
+
link = "#{data['links']['metadata']}#{SLIS_PATH}"
|
|
471
|
+
|
|
472
|
+
# TODO: Review what to do with passed extra argument
|
|
473
|
+
Metadata.new GoodData.get(link)
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
# Gets project state
|
|
477
|
+
#
|
|
478
|
+
# @return [String] Project state
|
|
479
|
+
def state
|
|
480
|
+
data['content']['state'].downcase.to_sym if data['content'] && data['content']['state']
|
|
481
|
+
end
|
|
482
|
+
|
|
483
|
+
# Gets project summary
|
|
484
|
+
#
|
|
485
|
+
# @return [String] Project summary
|
|
486
|
+
def summary
|
|
487
|
+
data['meta']['summary'] if data['meta']
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# Gets project title
|
|
491
|
+
#
|
|
492
|
+
# @return [String] Project title
|
|
493
|
+
def title
|
|
494
|
+
data['meta']['title'] if data['meta']
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
# Gets project update date
|
|
498
|
+
#
|
|
499
|
+
# @return [DateTime] Date time of last update
|
|
500
|
+
def updated
|
|
501
|
+
DateTime.parse(@json['meta']['updated'])
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# Uploads file to project
|
|
505
|
+
#
|
|
506
|
+
# @param file File to be uploaded
|
|
507
|
+
# @param schema Schema to be used
|
|
508
|
+
def upload(file, schema, mode = 'FULL')
|
|
509
|
+
schema.upload file, self, mode
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
def uri
|
|
513
|
+
data['links']['self'] if data && data['links'] && data['links']['self']
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
# List of users in project
|
|
517
|
+
#
|
|
518
|
+
# @return [Array<GoodData::User>] List of users
|
|
519
|
+
def users
|
|
520
|
+
res = []
|
|
521
|
+
|
|
522
|
+
tmp = GoodData.get @json['project']['links']['users']
|
|
523
|
+
tmp['users'].map do |user|
|
|
524
|
+
res << GoodData::User.new(user)
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
res
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
# Run validation on project
|
|
531
|
+
# Valid settins for validation are (default all):
|
|
532
|
+
# ldm - Checks the consistency of LDM objects.
|
|
533
|
+
# pdm Checks LDM to PDM mapping consistency, also checks PDM reference integrity.
|
|
534
|
+
# metric_filter - Checks metadata for inconsistent metric filters.
|
|
535
|
+
# invalid_objects - Checks metadata for invalid/corrupted objects.
|
|
536
|
+
# asyncTask response
|
|
537
|
+
def validate(filters = %w(ldm, pdm, metric_filter, invalid_objects))
|
|
538
|
+
response = GoodData.post "#{GoodData.project.md['validate-project']}", 'validateProject' => filters
|
|
539
|
+
polling_link = response['asyncTask']['link']['poll']
|
|
540
|
+
polling_result = GoodData.get(polling_link)
|
|
541
|
+
while polling_result['wTaskStatus'] && polling_result['wTaskStatus']['status'] == 'RUNNING'
|
|
542
|
+
sleep(3)
|
|
543
|
+
polling_result = GoodData.get(polling_link)
|
|
544
|
+
end
|
|
545
|
+
polling_result
|
|
278
546
|
end
|
|
279
547
|
|
|
548
|
+
alias_method :to_json, :json
|
|
549
|
+
alias_method :raw_data, :json
|
|
280
550
|
end
|
|
281
551
|
end
|