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
@@ -0,0 +1,389 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'multi_json'
4
+ require 'rest-client'
5
+
6
+ require_relative '../version'
7
+
8
+ 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
47
+ #
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
60
+ end
61
+
62
+ # Set the GoodData account credentials.
63
+ #
64
+ # This have to be performed before any calls to the API.
65
+ #
66
+ # @param username The GoodData account username
67
+ # @param password The GoodData account password
68
+ #
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
76
+
77
+ @headers = options[:headers] || {}
78
+
79
+ default_headers = {
80
+ :content_type => :json,
81
+ :accept => [:json, :zip],
82
+ :user_agent => GoodData.gem_version_string
83
+ }
84
+ default_headers.merge! @headers
85
+
86
+ @server = RestClient::Resource.new @url,
87
+ :timeout => @options[:timeout],
88
+ :headers => default_headers
89
+
90
+ @server = create_server_connection(@url, @options)
91
+ end
92
+
93
+ # Returns the user JSON object of the currently logged in GoodData user account.
94
+ def user
95
+ ensure_connection
96
+ @user
97
+ end
98
+
99
+ # Performs a HTTP GET request.
100
+ #
101
+ # Retuns the JSON response formatted as a Hash object.
102
+ #
103
+ # @param path The HTTP path on the GoodData server (must be prefixed with a forward slash)
104
+ #
105
+ # ### Examples
106
+ #
107
+ # Connection.new(username, password).get '/gdc/projects'
108
+ #
109
+ def get(path, options = {})
110
+ GoodData.logger.debug "GET #{@server}#{path}"
111
+ ensure_connection
112
+ b = proc { @server[path].get cookies }
113
+ process_response(options, &b)
114
+ end
115
+
116
+ # Performs a HTTP POST request.
117
+ #
118
+ # Retuns the JSON response formatted as a Hash object.
119
+ #
120
+ # @param path The HTTP path on the GoodData server (must be prefixed with a forward slash)
121
+ # @param data The payload data in the format of a Hash object
122
+ #
123
+ # ### Examples
124
+ #
125
+ # Connection.new(username, password).post '/gdc/projects', { ... }
126
+ #
127
+ def post(path, data, options = {})
128
+ GoodData.logger.debug("POST #{@server}#{path}, payload: #{scrub_params(data, [:password, :login, :authorizationToken])}")
129
+ ensure_connection
130
+ payload = data.is_a?(Hash) ? data.to_json : data
131
+ b = proc { @server[path].post payload, cookies }
132
+ process_response(options, &b)
133
+ end
134
+
135
+ # Performs a HTTP PUT request.
136
+ #
137
+ # Retuns the JSON response formatted as a Hash object.
138
+ #
139
+ # @param path The HTTP path on the GoodData server (must be prefixed with a forward slash)
140
+ # @param data The payload data in the format of a Hash object
141
+ #
142
+ # ### Examples
143
+ #
144
+ # Connection.new(username, password).put '/gdc/projects', { ... }
145
+ #
146
+ def put(path, data, options = {})
147
+ payload = data.is_a?(Hash) ? data.to_json : data
148
+ GoodData.logger.debug "PUT #{@server}#{path}, payload: #{payload}"
149
+ ensure_connection
150
+ b = proc { @server[path].put payload, cookies }
151
+ process_response(options, &b)
152
+ end
153
+
154
+ # Performs a HTTP DELETE request.
155
+ #
156
+ # Retuns the JSON response formatted as a Hash object.
157
+ #
158
+ # @param path The HTTP path on the GoodData server (must be prefixed with a forward slash)
159
+ #
160
+ # ### Examples
161
+ #
162
+ # Connection.new(username, password).delete '/gdc/project/1'
163
+ #
164
+ def delete(path, options = {})
165
+ GoodData.logger.debug "DELETE #{@server}#{path}"
166
+ ensure_connection
167
+ b = proc { @server[path].delete cookies }
168
+ process_response(options, &b)
169
+ end
170
+
171
+ # Get the cookies associated with the current connection.
172
+ def cookies
173
+ @cookies ||= { :cookies => {} }
174
+ end
175
+
176
+ # Set the cookies used when communicating with the GoodData API.
177
+ def merge_cookies!(cookies)
178
+ self.cookies
179
+ @cookies[:cookies].merge! cookies
180
+ end
181
+
182
+ # Returns true if a connection have been established to the GoodData API
183
+ # and the login was successful.
184
+ def logged_in?
185
+ @status == :logged_in
186
+ end
187
+
188
+ def url=(url = nil)
189
+ @url = url || DEFAULT_URL
190
+ @server = create_server_connection(@url, @options)
191
+ end
192
+
193
+ # The connection will automatically be established once it's needed, which it
194
+ # usually is when either the user, get, post or delete method is called. If you
195
+ # want to force a connection (or a re-connect) you can use this method.
196
+ def connect!
197
+ connect
198
+ end
199
+
200
+ # Uploads a file to GoodData server
201
+ # /uploads/ resources are special in that they use a different
202
+ # host and a basic authentication.
203
+ def upload(file, options = {})
204
+ ensure_connection
205
+
206
+ dir = options[:directory] || ''
207
+ staging_uri = options[:staging_url].to_s
208
+ url = dir.empty? ? staging_uri : URI.join(staging_uri, "#{dir}/").to_s
209
+
210
+ # Make a directory, if needed
211
+ unless dir.empty?
212
+ method = :get
213
+ GoodData.logger.debug "#{method}: #{url}"
214
+ begin
215
+ # first check if it does exits
216
+ RestClient::Request.execute({
217
+ :method => method,
218
+ :url => url,
219
+ :timeout => @options[:timeout],
220
+ :headers => {
221
+ :user_agent => GoodData.gem_version_string
222
+ }
223
+ }.merge(cookies)
224
+ )
225
+ rescue RestClient::Exception => e
226
+ if e.http_code == 404
227
+ method = :mkcol
228
+ GoodData.logger.debug "#{method}: #{url}"
229
+ RestClient::Request.execute({
230
+ :method => method,
231
+ :url => url,
232
+ :timeout => @options[:timeout],
233
+ :headers => {
234
+ :user_agent => GoodData.gem_version_string
235
+ }
236
+ }.merge(cookies))
237
+ end
238
+ end
239
+ end
240
+
241
+ payload = options[:stream] ? 'file' : File.read(file)
242
+ filename = options[:filename] || options[:stream] ? 'randome-filename.txt' : File.basename(file)
243
+
244
+ # Upload the file
245
+ # puts "uploading the file #{URI.join(url, filename).to_s}"
246
+ req = RestClient::Request.new(
247
+ :method => :put,
248
+ :url => URI.join(url, filename).to_s,
249
+ :timeout => @options[:timeout],
250
+ :headers => {
251
+ :user_agent => GoodData.gem_version_string
252
+ },
253
+ :payload => payload,
254
+ :raw_response => true,
255
+ :user => @username,
256
+ :password => @password
257
+ )
258
+ # .merge(cookies))
259
+ req.execute
260
+ true
261
+ end
262
+
263
+ def download(what, where, options = {})
264
+ staging_uri = options[:staging_url].to_s
265
+ url = staging_uri + what
266
+ req = RestClient::Request.new(
267
+ :method => 'GET',
268
+ :url => url,
269
+ :user => @username,
270
+ :password => @password)
271
+
272
+ if where.is_a?(String)
273
+ File.open(where, 'w') do |f|
274
+ req.execute do |chunk, x, y|
275
+ f.write chunk
276
+ end
277
+ end
278
+ else
279
+ # Assume it is a IO stream
280
+ req.execute do |chunk, x, y|
281
+ where.write chunk
282
+ end
283
+ end
284
+ end
285
+
286
+ def connected?
287
+ @status == :logged_in
288
+ end
289
+
290
+ def disconnect
291
+ if connected? && GoodData.connection.user['state']
292
+ GoodData.delete(GoodData.connection.user['state'])
293
+ @status = :not_connected
294
+ end
295
+ end
296
+
297
+ private
298
+
299
+ def create_server_connection(url, options)
300
+ RestClient::Resource.new url,
301
+ :timeout => options[:timeout],
302
+ :headers => {
303
+ :content_type => :json,
304
+ :accept => [:json, :zip],
305
+ :user_agent => GoodData.gem_version_string
306
+ }
307
+ end
308
+
309
+ def ensure_connection
310
+ connect if @status == :not_connected
311
+ end
312
+
313
+ def connect
314
+ GoodData.logger.info 'Connecting to GoodData...'
315
+ @status = :connecting
316
+ authenticate
317
+ end
318
+
319
+ def authenticate
320
+ credentials = {
321
+ 'postUserLogin' => {
322
+ 'login' => @username,
323
+ 'password' => @password,
324
+ 'remember' => 1
325
+ }
326
+ }
327
+ GoodData.logger.debug 'Logging in...'
328
+ @user = post(LOGIN_PATH, credentials, :dont_reauth => true)['userLogin']
329
+ refresh_token :dont_reauth => true # avoid infinite loop if refresh_token fails with 401
330
+
331
+ @status = :logged_in
332
+ end
333
+
334
+ def process_response(options = {}, &block)
335
+ begin
336
+ response = block.call
337
+ rescue RestClient::Unauthorized
338
+ raise $ERROR_INFO if options[:dont_reauth]
339
+ refresh_token
340
+ response = block.call
341
+ end
342
+ merge_cookies! response.cookies
343
+ content_type = response.headers[:content_type]
344
+ return response if options[:process] == false
345
+
346
+ if content_type == 'application/json' || content_type == 'application/json;charset=UTF-8'
347
+ result = response.to_str == '""' ? {} : MultiJson.load(response.to_str)
348
+ GoodData.logger.debug "Response: #{result.inspect}"
349
+ elsif content_type == 'application/zip'
350
+ result = response
351
+ GoodData.logger.debug 'Response: a zipped stream'
352
+ elsif response.headers[:content_length].to_s == '0'
353
+ result = nil
354
+ GoodData.logger.debug 'Response: Empty response possibly 204'
355
+ elsif response.code == 204
356
+ result = nil
357
+ GoodData.logger.debug 'Response: 204 no content'
358
+ else
359
+ fail "Unsupported response content type '%s':\n%s" % [content_type, response.to_str[0..127]]
360
+ end
361
+ result
362
+ rescue RestClient::Exception => e
363
+ GoodData.logger.debug "Response: #{e.response}"
364
+ raise $ERROR_INFO
365
+ end
366
+
367
+ def refresh_token(options = {})
368
+ GoodData.logger.debug 'Getting authentication token...'
369
+ begin
370
+ get TOKEN_PATH, :dont_reauth => true # avoid infinite loop GET fails with 401
371
+ rescue RestClient::Unauthorized
372
+ raise $ERROR_INFO if options[:dont_reauth]
373
+ authenticate
374
+ end
375
+ end
376
+
377
+ def scrub_params(params, keys)
378
+ keys = keys.reduce([]) { |a, e| a.concat([e.to_s, e.to_sym]) }
379
+
380
+ new_params = Marshal.load(Marshal.dump(params))
381
+ GoodData::Helpers.hash_dfs(new_params) do |k, key|
382
+ keys.each do |key_to_scrub|
383
+ k[key_to_scrub] = ('*' * k[key_to_scrub].length) if k && k.key?(key_to_scrub) && k[key_to_scrub]
384
+ end
385
+ end
386
+ new_params
387
+ end
388
+ end
389
+ end
@@ -1,7 +1,8 @@
1
1
  # encoding: UTF-8
2
2
 
3
- module GoodData
4
- # Core of GoodData Gem
5
- class Core
6
- end
3
+ require 'pathname'
4
+
5
+ base = Pathname(__FILE__).dirname.expand_path
6
+ Dir.glob(base + '*.rb').each do |file|
7
+ require file
7
8
  end
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative 'nil_logger'
4
+ require_relative 'threaded'
5
+
6
+ module GoodData
7
+ class << self
8
+ attr_writer :logger
9
+
10
+ # Turn logging on
11
+ #
12
+ # ### Example
13
+ #
14
+ # GoodData.logging_on
15
+ #
16
+ def logging_on
17
+ GoodData.logger = Logger.new(STDOUT) if logger.is_a? NilLogger
18
+ end
19
+
20
+ # Turn logging on
21
+ #
22
+ # ### Example
23
+ #
24
+ # GoodData.logging_off
25
+ #
26
+ def logging_off
27
+ GoodData.logger = NilLogger.new
28
+ end
29
+
30
+ def logging_on?
31
+ !GoodData.logger.instance_of?(NilLogger)
32
+ end
33
+
34
+ # Returns the logger instance. The default implementation
35
+ # does not log anything
36
+ # For some serious logging, set the logger instance using
37
+ # the logger= method
38
+ #
39
+ # ### Example
40
+ #
41
+ # require 'logger'
42
+ # GoodData.logger = Logger.new(STDOUT)
43
+ #
44
+ def logger
45
+ @logger ||= NilLogger.new
46
+ end
47
+ end
48
+ end