gooddata 0.6.0 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (208) hide show
  1. checksums.yaml +13 -5
  2. data/.rubocop.yml +23 -0
  3. data/.travis.yml +9 -4
  4. data/CLI.md +439 -0
  5. data/Gemfile +0 -1
  6. data/README.md +2 -2
  7. data/Rakefile +60 -8
  8. data/doc/templates/default/module/setup.rb +1 -1
  9. data/examples.rb +2 -0
  10. data/gooddata +2 -0
  11. data/gooddata.gemspec +12 -8
  12. data/lib/gooddata.rb +0 -2
  13. data/lib/gooddata/bricks/base_downloader.rb +52 -47
  14. data/lib/gooddata/bricks/brick.rb +20 -31
  15. data/lib/gooddata/bricks/bricks.rb +1 -1
  16. data/lib/gooddata/bricks/middleware/base_middleware.rb +9 -7
  17. data/lib/gooddata/bricks/middleware/bench_middleware.rb +12 -10
  18. data/lib/gooddata/bricks/middleware/bulk_salesforce_middleware.rb +28 -28
  19. data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +20 -16
  20. data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +21 -19
  21. data/lib/gooddata/bricks/middleware/logger_middleware.rb +10 -8
  22. data/lib/gooddata/bricks/middleware/restforce_middleware.rb +36 -34
  23. data/lib/gooddata/bricks/middleware/stdout_middleware.rb +11 -9
  24. data/lib/gooddata/bricks/middleware/twitter_middleware.rb +14 -12
  25. data/lib/gooddata/bricks/pipeline.rb +28 -0
  26. data/lib/gooddata/bricks/utils.rb +10 -8
  27. data/lib/gooddata/cli/cli.rb +1 -6
  28. data/lib/gooddata/cli/commands/auth_cmd.rb +1 -1
  29. data/lib/gooddata/cli/commands/console_cmd.rb +7 -5
  30. data/lib/gooddata/cli/commands/domain_cmd.rb +45 -0
  31. data/lib/gooddata/cli/commands/process_cmd.rb +42 -5
  32. data/lib/gooddata/cli/commands/project_cmd.rb +96 -36
  33. data/lib/gooddata/cli/commands/projects_cmd.rb +21 -0
  34. data/lib/gooddata/cli/commands/role_cmd.rb +28 -0
  35. data/lib/gooddata/cli/commands/run_ruby_cmd.rb +5 -5
  36. data/lib/gooddata/cli/commands/scaffold_cmd.rb +1 -1
  37. data/lib/gooddata/cli/commands/{profile_cmd.rb → user_cmd.rb} +7 -9
  38. data/lib/gooddata/cli/shared.rb +3 -2
  39. data/lib/gooddata/client.rb +16 -304
  40. data/lib/gooddata/commands/api.rb +13 -5
  41. data/lib/gooddata/commands/auth.rb +47 -40
  42. data/lib/gooddata/commands/base.rb +4 -2
  43. data/lib/gooddata/commands/commands.rb +1 -1
  44. data/lib/gooddata/commands/datasets.rb +20 -7
  45. data/lib/gooddata/commands/domain.rb +23 -0
  46. data/lib/gooddata/commands/process.rb +23 -117
  47. data/lib/gooddata/commands/project.rb +147 -0
  48. data/lib/gooddata/commands/projects.rb +8 -102
  49. data/lib/gooddata/commands/role.rb +26 -0
  50. data/lib/gooddata/commands/runners.rb +41 -38
  51. data/lib/gooddata/commands/scaffold.rb +46 -43
  52. data/lib/gooddata/commands/user.rb +33 -0
  53. data/lib/gooddata/connection.rb +43 -353
  54. data/lib/gooddata/core/connection.rb +389 -0
  55. data/lib/gooddata/core/core.rb +5 -4
  56. data/lib/gooddata/core/logging.rb +48 -0
  57. data/lib/gooddata/core/nil_logger.rb +13 -0
  58. data/lib/gooddata/core/project.rb +70 -0
  59. data/lib/gooddata/core/rest.rb +120 -0
  60. data/lib/gooddata/core/threaded.rb +14 -0
  61. data/lib/gooddata/core/user.rb +19 -0
  62. data/lib/gooddata/data/data.rb +2 -1
  63. data/lib/gooddata/data/guesser.rb +16 -12
  64. data/lib/gooddata/exceptions/command_failed.rb +1 -1
  65. data/lib/gooddata/exceptions/exceptions.rb +2 -1
  66. data/lib/gooddata/exceptions/no_project_error.rb +11 -0
  67. data/lib/gooddata/exceptions/project_not_found.rb +1 -1
  68. data/lib/gooddata/extensions/big_decimal.rb +6 -2
  69. data/lib/gooddata/extract.rb +10 -8
  70. data/lib/gooddata/goodzilla/goodzilla.rb +61 -59
  71. data/lib/gooddata/helpers.rb +15 -9
  72. data/lib/gooddata/models/account_settings.rb +124 -0
  73. data/lib/gooddata/models/attributes/anchor.rb +37 -0
  74. data/lib/gooddata/models/attributes/attributes.rb +8 -0
  75. data/lib/gooddata/models/attributes/date_attribute.rb +25 -0
  76. data/lib/gooddata/models/attributes/time_attribute.rb +24 -0
  77. data/lib/gooddata/models/columns/attribute.rb +71 -0
  78. data/lib/gooddata/models/columns/columns.rb +8 -0
  79. data/lib/gooddata/models/columns/date_column.rb +63 -0
  80. data/lib/gooddata/models/columns/fact_model.rb +54 -0
  81. data/lib/gooddata/models/columns/label.rb +55 -0
  82. data/lib/gooddata/models/columns/reference.rb +57 -0
  83. data/lib/gooddata/models/dashboard_builder.rb +26 -0
  84. data/lib/gooddata/models/data_result.rb +10 -9
  85. data/lib/gooddata/models/domain.rb +131 -0
  86. data/lib/gooddata/models/empty_result.rb +5 -8
  87. data/lib/gooddata/models/facts/facts.rb +8 -0
  88. data/lib/gooddata/models/facts/time_fact.rb +20 -0
  89. data/lib/gooddata/models/folders/attribute_folder.rb +20 -0
  90. data/lib/gooddata/models/folders/fact_folder.rb +20 -0
  91. data/lib/gooddata/models/folders/folders.rb +8 -0
  92. data/lib/gooddata/models/invitation.rb +78 -0
  93. data/lib/gooddata/models/links.rb +6 -6
  94. data/lib/gooddata/models/md_object.rb +25 -0
  95. data/lib/gooddata/models/metadata.rb +160 -62
  96. data/lib/gooddata/models/metadata/attribute.rb +81 -0
  97. data/lib/gooddata/models/metadata/column.rb +61 -0
  98. data/lib/gooddata/models/{dashboard.rb → metadata/dashboard.rb} +12 -7
  99. data/lib/gooddata/models/{data_set.rb → metadata/data_set.rb} +5 -4
  100. data/lib/gooddata/models/metadata/date_dimension.rb +26 -0
  101. data/lib/gooddata/models/metadata/display_form.rb +61 -0
  102. data/lib/gooddata/models/metadata/fact.rb +36 -0
  103. data/lib/gooddata/models/metadata/folder.rb +24 -0
  104. data/lib/gooddata/models/metadata/metadata.rb +8 -0
  105. data/lib/gooddata/models/metadata/metric.rb +197 -0
  106. data/lib/gooddata/models/metadata/report.rb +115 -0
  107. data/lib/gooddata/models/{report_definition.rb → metadata/report_definition.rb} +16 -10
  108. data/lib/gooddata/models/metadata/schema.rb +227 -0
  109. data/lib/gooddata/models/model.rb +38 -1339
  110. data/lib/gooddata/models/models.rb +5 -2
  111. data/lib/gooddata/models/module_constants.rb +29 -0
  112. data/lib/gooddata/models/process.rb +142 -13
  113. data/lib/gooddata/models/profile.rb +4 -6
  114. data/lib/gooddata/models/project.rb +406 -136
  115. data/lib/gooddata/models/project_blueprint.rb +221 -0
  116. data/lib/gooddata/models/project_builder.rb +136 -0
  117. data/lib/gooddata/models/project_creator.rb +138 -0
  118. data/lib/gooddata/models/project_metadata.rb +11 -10
  119. data/lib/gooddata/models/project_role.rb +92 -0
  120. data/lib/gooddata/models/references/date_reference.rb +44 -0
  121. data/lib/gooddata/models/references/references.rb +8 -0
  122. data/lib/gooddata/models/references/time_reference.rb +13 -0
  123. data/lib/gooddata/models/report_data_result.rb +11 -11
  124. data/lib/gooddata/models/schedule.rb +284 -0
  125. data/lib/gooddata/models/schema_blueprint.rb +158 -0
  126. data/lib/gooddata/models/schema_builder.rb +81 -0
  127. data/lib/gooddata/models/tab_builder.rb +23 -0
  128. data/lib/gooddata/models/user.rb +165 -0
  129. data/lib/gooddata/version.rb +1 -1
  130. data/lib/templates/project/data/devs.csv +1 -1
  131. data/lib/templates/project/data/repos.csv +1 -1
  132. data/lib/templates/project/model/model.rb.erb +7 -11
  133. data/spec/bricks/bricks_spec.rb +2 -0
  134. data/spec/data/test-ci-data.csv +2 -0
  135. data/spec/data/test_project_model_spec.json +7 -27
  136. data/spec/helpers/blueprint_helper.rb +2 -0
  137. data/spec/helpers/cli_helper.rb +2 -0
  138. data/spec/helpers/connection_helper.rb +14 -1
  139. data/spec/helpers/project_helper.rb +16 -0
  140. data/spec/helpers/schema_helper.rb +16 -0
  141. data/spec/integration/command_projects_spec.rb +7 -7
  142. data/spec/integration/create_from_template_spec.rb +2 -2
  143. data/spec/integration/full_project_spec.rb +160 -7
  144. data/spec/integration/partial_md_export_import_spec.rb +3 -3
  145. data/spec/logging_in_logging_out_spec.rb +2 -1
  146. data/spec/spec_helper.rb +26 -4
  147. data/spec/unit/bricks/bricks_spec.rb +15 -7
  148. data/spec/unit/bricks/middleware/bench_middleware_spec.rb +2 -0
  149. data/spec/unit/bricks/middleware/bulk_salesforce_middleware_spec.rb +2 -0
  150. data/spec/unit/bricks/middleware/gooddata_middleware_spec.rb +2 -0
  151. data/spec/unit/bricks/middleware/logger_middleware_spec.rb +2 -0
  152. data/spec/unit/bricks/middleware/restforce_middleware_spec.rb +2 -0
  153. data/spec/unit/bricks/middleware/stdout_middleware_spec.rb +2 -0
  154. data/spec/unit/bricks/middleware/twitter_middleware_spec.rb +2 -0
  155. data/spec/unit/cli/cli_spec.rb +2 -0
  156. data/spec/unit/cli/commands/cmd_api_spec.rb +23 -15
  157. data/spec/unit/cli/commands/cmd_auth_spec.rb +8 -4
  158. data/spec/unit/cli/commands/cmd_domain_spec.rb +82 -0
  159. data/spec/unit/cli/commands/cmd_process_spec.rb +29 -13
  160. data/spec/unit/cli/commands/cmd_project_spec.rb +51 -30
  161. data/spec/unit/cli/commands/cmd_role_spec.rb +44 -0
  162. data/spec/unit/cli/commands/cmd_run_ruby_spec.rb +8 -4
  163. data/spec/unit/cli/commands/cmd_scaffold_spec.rb +48 -11
  164. data/spec/unit/cli/commands/cmd_user_spec.rb +29 -0
  165. data/spec/unit/commands/command_api_spec.rb +1 -1
  166. data/spec/unit/commands/command_auth_spec.rb +100 -18
  167. data/spec/unit/commands/command_dataset_spec.rb +4 -0
  168. data/spec/unit/commands/command_process_spec.rb +9 -4
  169. data/spec/unit/commands/command_projects_spec.rb +10 -6
  170. data/spec/unit/commands/command_scaffold_spec.rb +5 -1
  171. data/spec/unit/commands/command_user_spec.rb +22 -0
  172. data/spec/unit/core/connection_spec.rb +35 -6
  173. data/spec/unit/core/logging_spec.rb +65 -0
  174. data/spec/unit/core/nil_logger_spec.rb +9 -0
  175. data/spec/unit/core/project_spec.rb +51 -0
  176. data/spec/unit/core/rest_spec.rb +33 -0
  177. data/spec/unit/data/guesser_spec.rb +5 -0
  178. data/spec/unit/godzilla/goodzilla_spec.rb +2 -0
  179. data/spec/unit/models/account_settings_spec.rb +28 -0
  180. data/spec/unit/models/anchor_spec.rb +32 -0
  181. data/spec/unit/models/attribute_column_spec.rb +7 -0
  182. data/spec/unit/models/domain_spec.rb +45 -0
  183. data/spec/unit/models/invitation_spec.rb +13 -0
  184. data/spec/unit/models/md_object_spec.rb +47 -0
  185. data/spec/unit/models/metric.rb +92 -0
  186. data/spec/unit/{model → models}/model_spec.rb +9 -7
  187. data/spec/unit/models/project_blueprint_spec.rb +202 -0
  188. data/spec/unit/models/project_creator.rb +73 -0
  189. data/spec/unit/models/project_role_spec.rb +90 -0
  190. data/spec/unit/models/project_spec.rb +143 -0
  191. data/spec/unit/models/schedule_spec.rb +491 -0
  192. data/spec/unit/{model → models}/schema_builder_spec.rb +2 -0
  193. data/spec/unit/{model → models}/tools_spec.rb +13 -7
  194. data/spec/unit/models/user_spec.rb +16 -0
  195. data/test/test_upload.rb +2 -0
  196. metadata +189 -86
  197. data/lib/gooddata/commands/profile.rb +0 -11
  198. data/lib/gooddata/models/attribute.rb +0 -29
  199. data/lib/gooddata/models/display_form.rb +0 -9
  200. data/lib/gooddata/models/fact.rb +0 -19
  201. data/lib/gooddata/models/metric.rb +0 -99
  202. data/lib/gooddata/models/report.rb +0 -89
  203. data/spec/data/blueprint_valid.json +0 -37
  204. data/spec/unit/cli/commands/cmd_profile_spec.rb +0 -16
  205. data/spec/unit/commands/command_profile_spec.rb +0 -18
  206. data/spec/unit/core/core_spec.rb +0 -7
  207. data/spec/unit/model/blueprint_spec.rb +0 -132
  208. data/spec/unit/model/project_blueprint_spec.rb +0 -44
@@ -1,109 +1,15 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module GoodData::Command
4
- class Projects
5
- class << self
6
- def list
7
- GoodData::Project.all
8
- end
9
-
10
- # Create new project based on options supplied
11
- def create(options={})
12
- title = options[:title]
13
- summary = options[:summary]
14
- template = options[:template]
15
- token = options[:token]
16
-
17
- GoodData::Project.create(:title => title, :summary => summary, :template => template, :auth_token => token)
18
- end
19
-
20
- # Show existing project
21
- def show(id)
22
- GoodData::Project[id]
23
- end
24
-
25
- # Clone existing project
26
- def clone(project_id, options)
27
- with_data = options[:with_data]
28
- with_users = options[:with_users]
29
- title = options[:title]
30
-
31
- export = {
32
- :exportProject => {
33
- :exportUsers => with_users ? 1 : 0,
34
- :exportData => with_data ? 1 : 0
35
- }
36
- }
37
-
38
- result = GoodData.post("/gdc/md/#{project_id}/maintenance/export", export)
39
- export_token = result['exportArtifact']['token']
40
- status_url = result['exportArtifact']['status']['uri']
41
-
42
- state = GoodData.get(status_url)['taskState']['status']
43
- while state == 'RUNNING'
44
- sleep 5
45
- result = GoodData.get(status_url)
46
- state = result['taskState']['status']
47
- end
48
-
49
- old_project = GoodData::Project[project_id]
50
- project_uri = self.create(options.merge({:title => "Clone of #{old_project.title}"}))
51
- new_project = GoodData::Project[project_uri]
52
-
53
- import = {
54
- :importProject => {
55
- :token => export_token
56
- }
57
- }
58
- result = GoodData.post("/gdc/md/#{new_project.obj_id}/maintenance/import", import)
59
- status_url = result['uri']
60
- state = GoodData.get(status_url)['taskState']['status']
61
- while state == 'RUNNING'
62
- sleep 5
63
- result = GoodData.get(status_url)
64
- state = result['taskState']['status']
3
+ require 'pathname'
4
+
5
+ module GoodData
6
+ module Command
7
+ class Projects
8
+ class << self
9
+ def list
10
+ GoodData::Project.all
65
11
  end
66
- true
67
- end
68
-
69
- # Delete existing project
70
- def delete(project_id)
71
- p = GoodData::Project[project_id]
72
- p.delete
73
- end
74
-
75
- # Get Spec and ID (of project)
76
- def get_spec_and_project_id(base_path)
77
- goodfile_path = GoodData::Helpers.find_goodfile(Pathname(base_path))
78
- fail 'Goodfile could not be located in any parent directory. Please make sure you are inside a gooddata project folder.' if goodfile_path.nil?
79
- goodfile = MultiJson.load(File.read(goodfile_path), :symbolize_keys => true)
80
- spec_path = goodfile[:model] || fail('You need to specify the path of the build spec')
81
- fail "Model path provided in Goodfile \"#{spec_path}\" does not exist" unless File.exist?(spec_path) && !File.directory?(spec_path)
82
-
83
- spec_path = Pathname(spec_path)
84
-
85
- content = File.read(spec_path)
86
- spec = if (spec_path.extname == '.rb')
87
- eval(content)
88
- elsif (spec_path.extname == '.json')
89
- MultiJson.load(spec_path, :symbolize_keys => true)
90
- end
91
- [spec, goodfile[:project_id]]
92
- end
93
-
94
- # Update project
95
- def update(options={})
96
- project = options[:project]
97
- project_id = project && project.pid
98
- fail 'You have to provide "project_id". You can either provide it through -p flag or even better way is to fill it in in your Goodfile under key "project_id". If you just started a project you have to create it first. One way might be through "gooddata project build"' if project_id.nil? || project_id.empty?
99
- GoodData::Model::ProjectCreator.migrate(:spec => options[:spec], :project => project_id)
100
- end
101
-
102
- # Build project
103
- def build(options={})
104
- GoodData::Model::ProjectCreator.migrate(:spec => options[:spec], :token => options[:token])
105
12
  end
106
13
  end
107
14
  end
108
15
  end
109
-
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../core/core'
4
+
5
+ module GoodData
6
+ module Command
7
+ class Role
8
+ class << self
9
+ def list(pid)
10
+ roles_response = GoodData.get("/gdc/projects/#{pid}/roles")
11
+
12
+ roles = {}
13
+ roles_response['projectRoles']['roles'].each do |role_uri|
14
+ r = GoodData.get(role_uri)
15
+ identifier = r['projectRole']['meta']['identifier']
16
+ roles[identifier] = {
17
+ :user_uri => r['projectRole']['links']['roleUsers'],
18
+ :uri => role_uri
19
+ }
20
+ end
21
+ roles
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,44 +1,47 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module GoodData::Command
4
- class Runners
5
- def self.run_ruby_locally(brick_dir, options={})
6
- pid = options[:project_id]
7
- fail 'You have to specify a project ID' if pid.nil?
8
- fail 'You have to specify directory of the brick run' if brick_dir.nil?
9
- fail 'You specified file as a birck run directory. You have to specify directory.' if File.exist?(brick_dir) && !File.directory?(brick_dir)
10
-
11
- params = options[:expanded_params] || {}
12
-
13
- GoodData.connection.connect!
14
- sst = GoodData.connection.cookies[:cookies]['GDCAuthSST']
15
- pwd = Pathname.new(Dir.pwd)
16
- logger_stream = STDOUT
17
-
18
- server_uri = URI(options[:server]) unless options[:server].nil?
19
- scheme = server_uri.nil? ? '' : server_uri.scheme
20
- hostname = server_uri.nil? ? '' : server_uri.host
21
-
22
- script_body = <<-script_body
23
- require 'fileutils'
24
- FileUtils::cd(\"#{pwd+brick_dir}\") do\
25
- require 'bundler/setup'
26
-
27
- $SCRIPT_PARAMS = {
28
- "GDC_SST" => \"#{sst}\",
29
- "GDC_PROJECT_ID" => \"#{pid}\",
30
- "GDC_PROTOCOL" => \"#{scheme}\",
31
- "GDC_HOSTNAME" => \"#{hostname}\",
32
- "GDC_LOGGER_FILE" => STDOUT,
33
- "GDC_ENV_LOCAL" => true
34
- }.merge(#{params})
35
- eval(File.read(\"./main.rb\"))
36
- end
37
- script_body
3
+ require 'pathname'
4
+
5
+ module GoodData
6
+ module Command
7
+ class Runners
8
+ def self.run_ruby_locally(brick_dir, options = {})
9
+ pid = options[:project_id]
10
+ fail 'You have to specify a project ID' if pid.nil?
11
+ fail 'You have to specify directory of the brick run' if brick_dir.nil?
12
+ fail 'You specified file as a birck run directory. You have to specify directory.' if File.exist?(brick_dir) && !File.directory?(brick_dir)
13
+
14
+ params = options[:expanded_params] || {}
15
+
16
+ GoodData.connection.connect!
17
+ sst = GoodData.connection.cookies[:cookies]['GDCAuthSST']
18
+ pwd = Pathname.new(Dir.pwd)
19
+
20
+ server_uri = URI(options[:server]) unless options[:server].nil?
21
+ scheme = server_uri.nil? ? '' : server_uri.scheme
22
+ hostname = server_uri.nil? ? '' : server_uri.host
23
+
24
+ script_body = <<-script_body
25
+ require 'fileutils'
26
+ FileUtils::cd(\"#{pwd + brick_dir}\") do\
27
+ require 'bundler/setup'
28
+
29
+ $SCRIPT_PARAMS = {
30
+ "GDC_SST" => \"#{sst}\",
31
+ "GDC_PROJECT_ID" => \"#{pid}\",
32
+ "GDC_PROTOCOL" => \"#{scheme}\",
33
+ "GDC_HOSTNAME" => \"#{hostname}\",
34
+ "GDC_LOGGER_FILE" => STDOUT,
35
+ "GDC_ENV_LOCAL" => true
36
+ }.merge(#{params})
37
+ eval(File.read(\"./main.rb\"))
38
+ end
39
+ script_body
38
40
 
39
- Bundler.with_clean_env do
40
- system('ruby', '-e', script_body)
41
+ Bundler.with_clean_env do
42
+ system('ruby', '-e', script_body)
43
+ end
41
44
  end
42
45
  end
43
46
  end
44
- end
47
+ end
@@ -2,62 +2,65 @@
2
2
 
3
3
  require 'erubis'
4
4
  require 'fileutils'
5
+ require 'pathname'
5
6
 
6
- module GoodData::Command
7
- class Scaffold
8
- TEMPLATES_PATH = Pathname(__FILE__) + '../../../templates'
7
+ module GoodData
8
+ module Command
9
+ class Scaffold
10
+ TEMPLATES_PATH = Pathname(__FILE__) + '../../../templates'
9
11
 
10
- class << self
11
- # Scaffolds new project
12
- # TODO: Add option for custom output dir
13
- def project(name)
14
- fail ArgumentError, 'No name specified' if name.nil?
12
+ class << self
13
+ # Scaffolds new project
14
+ # TODO: Add option for custom output dir
15
+ def project(name)
16
+ fail ArgumentError, 'No name specified' if name.nil?
15
17
 
16
- FileUtils.mkdir(name)
17
- FileUtils.cd(name) do
18
+ FileUtils.mkdir(name)
19
+ FileUtils.cd(name) do
18
20
 
19
- FileUtils.mkdir('model')
20
- FileUtils.cd('model') do
21
- input = File.read(TEMPLATES_PATH + 'project/model/model.rb.erb')
22
- eruby = Erubis::Eruby.new(input)
23
- File.open('model.rb', 'w') do |f|
24
- f.write(eruby.result(:name => name))
21
+ FileUtils.mkdir('model')
22
+ FileUtils.cd('model') do
23
+ input = File.read(TEMPLATES_PATH + 'project/model/model.rb.erb')
24
+ eruby = Erubis::Eruby.new(input)
25
+ File.open('model.rb', 'w') do |f|
26
+ f.write(eruby.result(:name => name))
27
+ end
25
28
  end
26
- end
27
29
 
28
- FileUtils.mkdir('data')
29
- FileUtils.cd('data') do
30
- FileUtils.cp(Dir.glob(TEMPLATES_PATH + 'project/data/*.csv'), '.')
31
- end
30
+ FileUtils.mkdir('data')
31
+ FileUtils.cd('data') do
32
+ FileUtils.cp(Dir.glob(TEMPLATES_PATH + 'project/data/*.csv'), '.')
33
+ end
32
34
 
33
- input = File.read(TEMPLATES_PATH + 'project/Goodfile.erb')
34
- eruby = Erubis::Eruby.new(input)
35
- File.open('Goodfile', 'w') do |f|
36
- f.write(eruby.result())
35
+ input = File.read(TEMPLATES_PATH + 'project/Goodfile.erb')
36
+ eruby = Erubis::Eruby.new(input)
37
+ File.open('Goodfile', 'w') do |f|
38
+ f.write(eruby.result)
39
+ end
37
40
  end
38
41
  end
39
- end
40
42
 
41
- # Scaffolds new brick
42
- # TODO: Add option for custom output dir
43
- def brick(name)
44
- fail ArgumentError, 'No name specified' if name.nil?
45
-
46
- FileUtils.mkdir(name)
47
- FileUtils.cd(name) do
48
- input = File.read(TEMPLATES_PATH + 'bricks/brick.rb.erb')
49
- eruby = Erubis::Eruby.new(input)
50
- File.open('brick.rb', 'w') do |f|
51
- f.write(eruby.result())
52
- end
43
+ # Scaffolds new brick
44
+ # TODO: Add option for custom output dir
45
+ def brick(name)
46
+ fail ArgumentError, 'No name specified' if name.nil?
47
+
48
+ FileUtils.mkdir(name)
49
+ FileUtils.cd(name) do
50
+ input = File.read(TEMPLATES_PATH + 'bricks/brick.rb.erb')
51
+ eruby = Erubis::Eruby.new(input)
52
+ File.open('brick.rb', 'w') do |f|
53
+ f.write(eruby.result)
54
+ end
53
55
 
54
- input = File.read(TEMPLATES_PATH + 'bricks/main.rb.erb')
55
- eruby = Erubis::Eruby.new(input)
56
- File.open('main.rb', 'w') do |f|
57
- f.write(eruby.result())
56
+ input = File.read(TEMPLATES_PATH + 'bricks/main.rb.erb')
57
+ eruby = Erubis::Eruby.new(input)
58
+ File.open('main.rb', 'w') do |f|
59
+ f.write(eruby.result)
60
+ end
58
61
  end
59
62
  end
60
63
  end
61
64
  end
62
65
  end
63
- end
66
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../core/core'
4
+
5
+ require 'highline/import'
6
+ require 'multi_json'
7
+
8
+ module GoodData
9
+ module Command
10
+ class User
11
+ class << self
12
+ def roles(pid)
13
+ roles_response = GoodData.get("/gdc/projects/#{pid}/roles")
14
+
15
+ roles = {}
16
+ roles_response['projectRoles']['roles'].each do |role_uri|
17
+ r = GoodData.get(role_uri)
18
+ identifier = r['projectRole']['meta']['identifier']
19
+ roles[identifier] = {
20
+ :user_uri => r['projectRole']['links']['roleUsers'],
21
+ :uri => role_uri
22
+ }
23
+ end
24
+ roles
25
+ end
26
+
27
+ def show
28
+ GoodData.profile.to_json
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,378 +1,68 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'multi_json'
4
- require 'rest-client'
5
-
6
- require_relative 'version'
3
+ require_relative 'core/connection'
4
+ require_relative 'core/logging'
5
+ require_relative 'core/threaded'
7
6
 
8
7
  module GoodData
9
- # # GoodData HTTP wrapper
10
- #
11
- # Provides a convenient HTTP wrapper for talking with the GoodData API.
12
- #
13
- # Remember that the connection is shared amongst the entire application.
14
- # Therefore you can't be logged in to more than _one_ GoodData account.
15
- # per session. Simultaneous connections to multiple GoodData accounts is not
16
- # supported at this time.
17
- #
18
- # The GoodData API is a RESTful API that communicates using JSON. This wrapper
19
- # makes sure that the session is stored between requests and that the JSON is
20
- # parsed both when sending and receiving.
21
- #
22
- # ## Usage
23
- #
24
- # Before a connection can be made to the GoodData API, you have to supply the user credentials like this:
25
- #
26
- # Connection.new(username, password)
27
- #
28
- # To send a HTTP request use either the get, post or delete methods documented below.
29
- #
30
- class Connection
31
- DEFAULT_URL = 'https://secure.gooddata.com'
32
- LOGIN_PATH = '/gdc/account/login'
33
- TOKEN_PATH = '/gdc/account/token'
34
-
35
- attr_reader(:auth_token, :url)
36
- attr_accessor :status, :options
37
-
38
- # Options:
39
- # * :tries - Number of retries to perform. Defaults to 1.
40
- # * :on - The Exception on which a retry will be performed. Defaults to Exception, which retries on any Exception.
41
- #
42
- # ### Example
43
- #
44
- # retryable(:tries => 1, :on => OpenURI::HTTPError) do
45
- # # your code here
46
- # end
8
+ class << self
9
+ # Returns the active GoodData connection earlier initialized via GoodData.connect call
47
10
  #
48
- def retryable(options = {}, &block)
49
- opts = {:tries => 1, :on => Exception}.merge(options)
50
-
51
- retry_exception, retries = opts[:on], opts[:tries]
52
-
53
- begin
54
- return yield
55
- rescue retry_exception
56
- retry if (retries -= 1) > 0
57
- end
58
-
59
- yield
11
+ # @see GoodData.connect
12
+ def connection
13
+ threaded[:connection] || fail('Please authenticate with GoodData.connect first')
60
14
  end
61
15
 
62
- # Set the GoodData account credentials.
63
- #
64
- # This have to be performed before any calls to the API.
16
+ # Connect to the GoodData API
65
17
  #
66
- # @param username The GoodData account username
67
- # @param password The GoodData account password
18
+ # @param options
19
+ # @param second_options
20
+ # @param third_options
68
21
  #
69
- def initialize(username, password, options = {})
70
- @status = :not_connected
71
- @username = username
72
- @password = password
73
- @url = options[:server] || DEFAULT_URL
74
- @auth_token = options[:gdc_temporary_token]
75
- @options = options
22
+ def connect(options = nil, second_options = nil, third_options = {})
23
+ GoodData.logger.debug 'GoodData#connect'
76
24
 
77
- @server = create_server_connection(@url, @options)
78
- end
25
+ if options.is_a? Hash
26
+ fail 'You have to provide login and password' if (options[:login].nil? || options[:login].empty?) && (options[:password].nil? || options[:password].empty?)
27
+ threaded[:connection] = Connection.new(options[:login], options[:password], options)
28
+ GoodData.project = options[:project] if options[:project]
29
+ elsif options.is_a?(String) && second_options.is_a?(String)
30
+ fail 'You have to provide login and password' if (options.nil? || options.empty?) && (second_options.nil? || second_options.empty?)
31
+ threaded[:connection] = Connection.new(options, second_options, third_options)
32
+ end
79
33
 
80
- # Returns the user JSON object of the currently logged in GoodData user account.
81
- def user
82
- ensure_connection
83
- @user
34
+ threaded[:connection]
84
35
  end
85
36
 
86
- # Performs a HTTP GET request.
87
- #
88
- # Retuns the JSON response formatted as a Hash object.
89
- #
90
- # @param path The HTTP path on the GoodData server (must be prefixed with a forward slash)
91
- #
92
- # ### Examples
93
- #
94
- # Connection.new(username, password).get '/gdc/projects'
95
- #
96
- def get(path, options = {})
97
- GoodData.logger.debug "GET #{@server}#{path}"
98
- ensure_connection
99
- b = Proc.new { @server[path].get cookies }
100
- process_response(options, &b)
101
- end
37
+ # Disconnect (logout) if logged in
38
+ def disconnect
39
+ GoodData.logger.debug 'GoodData#disconnect'
102
40
 
103
- # Performs a HTTP POST request.
104
- #
105
- # Retuns the JSON response formatted as a Hash object.
106
- #
107
- # @param path The HTTP path on the GoodData server (must be prefixed with a forward slash)
108
- # @param data The payload data in the format of a Hash object
109
- #
110
- # ### Examples
111
- #
112
- # Connection.new(username, password).post '/gdc/projects', { ... }
113
- #
114
- def post(path, data, options = {})
115
- GoodData.logger.debug("POST #{@server}#{path}, payload: #{scrub_params(data, [:password, :login, :authorizationToken])}")
116
- ensure_connection
117
- payload = data.is_a?(Hash) ? data.to_json : data
118
- b = Proc.new { @server[path].post payload, cookies }
119
- process_response(options, &b)
41
+ if threaded[:connection]
42
+ threaded[:connection].disconnect
43
+ threaded[:connection] = nil
44
+ end
120
45
  end
121
46
 
122
- # Performs a HTTP PUT request.
47
+ # Hepler for starting with SST easier
123
48
  #
124
- # Retuns the JSON response formatted as a Hash object.
49
+ # @param token SST token
50
+ # @param options Options get routed to connect eventually so everything that you can use there should be possible to use here.
125
51
  #
126
- # @param path The HTTP path on the GoodData server (must be prefixed with a forward slash)
127
- # @param data The payload data in the format of a Hash object
128
- #
129
- # ### Examples
130
- #
131
- # Connection.new(username, password).put '/gdc/projects', { ... }
132
- #
133
- def put(path, data, options = {})
134
- payload = data.is_a?(Hash) ? data.to_json : data
135
- GoodData.logger.debug "PUT #{@server}#{path}, payload: #{payload}"
136
- ensure_connection
137
- b = Proc.new { @server[path].put payload, cookies }
138
- process_response(options, &b)
52
+ def connect_with_sst(token, options = {})
53
+ create_authenticated_connection(options.merge(:cookies => { 'GDCAuthSST' => token }))
139
54
  end
140
55
 
141
- # Performs a HTTP DELETE request.
142
- #
143
- # Retuns the JSON response formatted as a Hash object.
144
- #
145
- # @param path The HTTP path on the GoodData server (must be prefixed with a forward slash)
56
+ # This method is aimed at creating an authenticated connection in case you do not hae pass/login but you have SST
146
57
  #
147
- # ### Examples
58
+ # @param options :server => optional GD server uri, If nil it secure will be used. :cookies => you can specify a hash of cookies
148
59
  #
149
- # Connection.new(username, password).delete '/gdc/project/1'
150
- #
151
- def delete(path, options = {})
152
- GoodData.logger.debug "DELETE #{@server}#{path}"
153
- ensure_connection
154
- b = Proc.new { @server[path].delete cookies }
155
- process_response(options, &b)
156
- end
157
-
158
- # Get the cookies associated with the current connection.
159
- def cookies
160
- @cookies ||= {:cookies => {}}
161
- end
162
-
163
- # Set the cookies used when communicating with the GoodData API.
164
- def merge_cookies!(cookies)
165
- self.cookies
166
- @cookies[:cookies].merge! cookies
167
- end
168
-
169
- # Returns true if a connection have been established to the GoodData API
170
- # and the login was successful.
171
- def logged_in?
172
- @status == :logged_in
173
- end
174
-
175
- def url=(url=nil)
176
- @url = url || DEFAULT_URL
177
- @server = create_server_connection(@url, @options)
178
- end
179
-
180
- # The connection will automatically be established once it's needed, which it
181
- # usually is when either the user, get, post or delete method is called. If you
182
- # want to force a connection (or a re-connect) you can use this method.
183
- def connect!
184
- connect
185
- end
186
-
187
- # Uploads a file to GoodData server
188
- # /uploads/ resources are special in that they use a different
189
- # host and a basic authentication.
190
- def upload(file, options={})
191
- ensure_connection
192
-
193
- dir = options[:directory] || ''
194
- staging_uri = options[:staging_url].to_s
195
- url = dir.empty? ? staging_uri : URI.join(staging_uri, "#{dir}/").to_s
196
-
197
- # Make a directory, if needed
198
- unless dir.empty? then
199
- method = :get
200
- GoodData.logger.debug "#{method}: #{url}"
201
- begin
202
- # first check if it does exits
203
- RestClient::Request.execute({
204
- :method => method,
205
- :url => url,
206
- :timeout => @options[:timeout],
207
- :headers => {
208
- :user_agent => GoodData.gem_version_string
209
- }}.merge(cookies)
210
- )
211
- rescue RestClient::Exception => e
212
- if e.http_code == 404 then
213
- method = :mkcol
214
- GoodData.logger.debug "#{method}: #{url}"
215
- RestClient::Request.execute({
216
- :method => method,
217
- :url => url,
218
- :timeout => @options[:timeout],
219
- :headers => {
220
- :user_agent => GoodData.gem_version_string
221
- }}.merge(cookies)
222
- )
223
- end
224
- end
225
- end
226
-
227
- payload = options[:stream] ? 'file' : File.read(file)
228
- filename = options[:filename] || options[:stream] ? 'randome-filename.txt' : File.basename(file)
229
-
230
- # Upload the file
231
- # puts "uploading the file #{URI.join(url, filename).to_s}"
232
- req = RestClient::Request.new({
233
- :method => :put,
234
- :url => URI.join(url, filename).to_s,
235
- :timeout => @options[:timeout],
236
- :headers => {
237
- :user_agent => GoodData.gem_version_string,
238
- },
239
- :payload => payload,
240
- :raw_response => true,
241
- :user => @username,
242
- :password => @password
243
- })
244
- # .merge(cookies))
245
- resp = req.execute
246
- true
247
- end
248
-
249
- def download(what, where, options={})
250
- staging_uri = options[:staging_url].to_s
251
- url = staging_uri + what
252
- req = RestClient::Request.new({
253
- :method => 'GET',
254
- :url => url,
255
- :user => @username,
256
- :password => @password
257
- })
258
-
259
- if where.is_a?(String)
260
- File.open(where, 'w') do |f|
261
- req.execute do |chunk, x, y|
262
- f.write chunk
263
- end
264
- end
265
- else
266
- # Assume it is a IO stream
267
- req.execute do |chunk, x, y|
268
- where.write chunk
269
- end
270
- end
271
- end
272
-
273
- def connected?
274
- @status == :logged_in
275
- end
276
-
277
- def disconnect
278
- if connected? && GoodData.connection.user['state']
279
- GoodData.delete(GoodData.connection.user['state'])
280
- @status = :not_connected
281
- end
282
- end
283
-
284
- private
285
-
286
- def create_server_connection(url, options)
287
- RestClient::Resource.new url,
288
- :timeout => options[:timeout],
289
- :headers => {
290
- :content_type => :json,
291
- :accept => [:json, :zip],
292
- :user_agent => GoodData::gem_version_string,
293
- }
294
- end
295
-
296
- def ensure_connection
297
- connect if @status == :not_connected
298
- end
299
-
300
- def connect
301
- GoodData.logger.info 'Connecting to GoodData...'
302
- @status = :connecting
303
- authenticate
304
- end
305
-
306
- def authenticate
307
- credentials = {
308
- 'postUserLogin' => {
309
- 'login' => @username,
310
- 'password' => @password,
311
- 'remember' => 1
312
- }
313
- }
314
- GoodData.logger.debug 'Logging in...'
315
- @user = post(LOGIN_PATH, credentials, :dont_reauth => true)['userLogin']
316
- refresh_token :dont_reauth => true # avoid infinite loop if refresh_token fails with 401
317
-
318
- @status = :logged_in
319
- end
320
-
321
- def process_response(options = {}, &block)
322
- begin
323
- begin
324
- response = block.call
325
- rescue RestClient::Unauthorized
326
- raise $! if options[:dont_reauth]
327
- refresh_token
328
- response = block.call
329
- end
330
- merge_cookies! response.cookies
331
- content_type = response.headers[:content_type]
332
- return response if options[:process] == false
333
-
334
- if content_type == "application/json" || content_type == "application/json;charset=UTF-8" then
335
- result = response.to_str == '""' ? {} : MultiJson.load(response.to_str)
336
- GoodData.logger.debug "Response: #{result.inspect}"
337
- elsif content_type == 'application/zip' then
338
- result = response
339
- GoodData.logger.debug 'Response: a zipped stream'
340
- elsif response.headers[:content_length].to_s == '0'
341
- result = nil
342
- GoodData.logger.debug 'Response: Empty response possibly 204'
343
- elsif response.code == 204
344
- result = nil
345
- GoodData.logger.debug 'Response: 204 no content'
346
- else
347
- raise "Unsupported response content type '%s':\n%s" % [content_type, response.to_str[0..127]]
348
- end
349
- result
350
- rescue RestClient::Exception => e
351
- GoodData.logger.debug "Response: #{e.response}"
352
- raise $!
353
- end
354
- end
355
-
356
- def refresh_token(options = {})
357
- GoodData.logger.debug 'Getting authentication token...'
358
- begin
359
- get TOKEN_PATH, :dont_reauth => true # avoid infinite loop GET fails with 401
360
- rescue RestClient::Unauthorized
361
- raise $! if options[:dont_reauth]
362
- authenticate
363
- end
364
- end
365
-
366
- def scrub_params(params, keys)
367
- keys = keys.reduce([]) { |memo, k| memo.concat([k.to_s, k.to_sym]) }
368
-
369
- new_params = Marshal.load(Marshal.dump(params))
370
- GoodData::Helpers.hash_dfs(new_params) do |k, key|
371
- keys.each do |key_to_scrub|
372
- k[key_to_scrub] = ('*' * k[key_to_scrub].length) if k && k.has_key?(key_to_scrub) && k[key_to_scrub]
373
- end
374
- end
375
- new_params
60
+ def create_authenticated_connection(options = {})
61
+ connect(options)
62
+ server_cookies = options[:cookies]
63
+ connection.merge_cookies!(server_cookies)
64
+ connection.status = :logged_in
65
+ connection
376
66
  end
377
67
  end
378
68
  end