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.
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