gooddata 0.6.11 → 0.6.12

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.travis.yml +5 -0
  4. data/CHANGELOG.md +34 -1
  5. data/CLI.md +1 -1
  6. data/authors.sh +4 -0
  7. data/lib/gooddata.rb +1 -1
  8. data/lib/gooddata/cli/commands/api_cmd.rb +0 -2
  9. data/lib/gooddata/cli/commands/auth_cmd.rb +0 -3
  10. data/lib/gooddata/cli/commands/console_cmd.rb +1 -2
  11. data/lib/gooddata/cli/commands/domain_cmd.rb +0 -2
  12. data/lib/gooddata/cli/commands/process_cmd.rb +0 -2
  13. data/lib/gooddata/cli/commands/project_cmd.rb +0 -2
  14. data/lib/gooddata/cli/commands/projects_cmd.rb +0 -2
  15. data/lib/gooddata/cli/commands/run_ruby_cmd.rb +2 -3
  16. data/lib/gooddata/cli/commands/scaffold_cmd.rb +0 -3
  17. data/lib/gooddata/cli/commands/user_cmd.rb +0 -2
  18. data/lib/gooddata/cli/shared.rb +1 -2
  19. data/lib/gooddata/commands/datawarehouse.rb +24 -0
  20. data/lib/gooddata/commands/process.rb +0 -1
  21. data/lib/gooddata/commands/project.rb +1 -1
  22. data/lib/gooddata/commands/scaffold.rb +0 -1
  23. data/lib/gooddata/core/connection.rb +376 -0
  24. data/lib/gooddata/core/logging.rb +13 -0
  25. data/lib/gooddata/core/rest.rb +40 -16
  26. data/lib/gooddata/exceptions/user_in_different_domain.rb +11 -0
  27. data/lib/gooddata/extensions/enumerable.rb +8 -0
  28. data/lib/gooddata/goodzilla/goodzilla.rb +24 -0
  29. data/lib/gooddata/helpers/global_helpers.rb +126 -12
  30. data/lib/gooddata/mixins/author.rb +11 -5
  31. data/lib/gooddata/mixins/is_dimension.rb +13 -0
  32. data/lib/gooddata/mixins/md_object_indexer.rb +17 -1
  33. data/lib/gooddata/mixins/md_object_query.rb +10 -2
  34. data/lib/gooddata/mixins/md_relations.rb +2 -2
  35. data/lib/gooddata/mixins/rest_resource.rb +1 -0
  36. data/lib/gooddata/models/data_result.rb +0 -1
  37. data/lib/gooddata/models/datawarehouse.rb +90 -0
  38. data/lib/gooddata/models/domain.rb +202 -76
  39. data/lib/gooddata/models/execution.rb +11 -0
  40. data/lib/gooddata/models/from_wire.rb +4 -4
  41. data/lib/gooddata/models/invitation.rb +0 -5
  42. data/lib/gooddata/models/membership.rb +121 -91
  43. data/lib/gooddata/models/metadata.rb +1 -2
  44. data/lib/gooddata/models/metadata/attribute.rb +7 -0
  45. data/lib/gooddata/models/metadata/dashboard.rb +1 -1
  46. data/lib/gooddata/models/metadata/dimension.rb +52 -0
  47. data/lib/gooddata/models/metadata/fact.rb +1 -1
  48. data/lib/gooddata/models/metadata/label.rb +21 -7
  49. data/lib/gooddata/models/metadata/metric.rb +1 -23
  50. data/lib/gooddata/models/metadata/report.rb +2 -2
  51. data/lib/gooddata/models/metadata/report_definition.rb +22 -2
  52. data/lib/gooddata/models/metadata/variable.rb +81 -0
  53. data/lib/gooddata/models/model.rb +2 -1
  54. data/lib/gooddata/models/process.rb +3 -4
  55. data/lib/gooddata/models/profile.rb +50 -82
  56. data/lib/gooddata/models/project.rb +170 -213
  57. data/lib/gooddata/models/project_blueprint.rb +14 -5
  58. data/lib/gooddata/models/project_creator.rb +2 -2
  59. data/lib/gooddata/models/schedule.rb +10 -8
  60. data/lib/gooddata/models/to_wire.rb +2 -2
  61. data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +67 -0
  62. data/lib/gooddata/models/user_filters/user_filter.rb +96 -0
  63. data/lib/gooddata/models/user_filters/user_filter_builder.rb +409 -0
  64. data/lib/gooddata/{rest/connections/connections.rb → models/user_filters/user_filters.rb} +1 -0
  65. data/lib/gooddata/models/user_filters/variable_user_filter.rb +14 -0
  66. data/lib/gooddata/rest/client.rb +32 -21
  67. data/lib/gooddata/rest/connection.rb +283 -11
  68. data/lib/gooddata/rest/connections/rest_client_connection.rb +47 -109
  69. data/lib/gooddata/version.rb +1 -1
  70. data/spec/data/column_based_permissions.csv +7 -0
  71. data/spec/data/column_based_permissions2.csv +6 -0
  72. data/spec/data/hello_world_process/hello_world.rb +3 -1
  73. data/spec/data/line_based_permissions.csv +3 -0
  74. data/spec/data/m_n_model/blueprint.json +76 -0
  75. data/spec/data/{model_view.json → wire_models/model_view.json} +0 -0
  76. data/spec/data/wire_models/nu_model.json +3046 -0
  77. data/spec/helpers/process_helper.rb +2 -2
  78. data/spec/helpers/project_helper.rb +29 -0
  79. data/spec/helpers/schedule_helper.rb +1 -1
  80. data/spec/integration/command_datawarehouse_spec.rb +32 -0
  81. data/spec/integration/create_project_spec.rb +0 -1
  82. data/spec/integration/full_process_schedule_spec.rb +13 -5
  83. data/spec/integration/full_project_spec.rb +2 -1
  84. data/spec/integration/over_to_user_filters_spec.rb +92 -0
  85. data/spec/integration/project_spec.rb +233 -0
  86. data/spec/integration/rest_spec.rb +209 -0
  87. data/spec/integration/user_filters_spec.rb +193 -0
  88. data/spec/integration/variables_spec.rb +196 -0
  89. data/spec/unit/commands/command_auth_spec.rb +0 -7
  90. data/spec/unit/commands/command_process_spec.rb +10 -13
  91. data/spec/unit/core/connection_spec.rb +0 -19
  92. data/spec/unit/helpers/global_helpers_spec.rb +57 -0
  93. data/spec/unit/models/domain_spec.rb +80 -40
  94. data/spec/unit/models/from_wire_spec.rb +8 -1
  95. data/spec/unit/models/params_spec.rb +6 -6
  96. data/spec/unit/models/profile_spec.rb +23 -22
  97. data/spec/unit/models/project_blueprint_spec.rb +1 -6
  98. data/spec/unit/models/project_spec.rb +331 -286
  99. data/spec/unit/models/schedule_spec.rb +39 -14
  100. data/spec/unit/models/user_filters_spec.rb +89 -0
  101. data/spec/unit/models/variable_spec.rb +259 -0
  102. metadata +31 -7
  103. data/lib/gooddata/rest/connections/dummy_connection.rb +0 -52
  104. data/spec/unit/core/rest_spec.rb +0 -106
@@ -3,6 +3,7 @@
3
3
  require 'pathname'
4
4
 
5
5
  base = Pathname(__FILE__).dirname.expand_path
6
+
6
7
  Dir.glob(base + '*.rb').each do |file|
7
8
  require_relative file
8
9
  end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+
3
+ module GoodData
4
+ class VariableUserFilter < UserFilter
5
+ # Creates or updates the variable user filter on the server
6
+ #
7
+ # @return [String]
8
+ def save
9
+ res = client.post(uri, :variable => @json)
10
+ @json['uri'] = res['uri']
11
+ self
12
+ end
13
+ end
14
+ end
@@ -4,7 +4,7 @@ require 'rest-client'
4
4
 
5
5
  require_relative '../helpers/auth_helpers'
6
6
 
7
- require_relative 'connections/connections'
7
+ require_relative 'connection'
8
8
  require_relative 'object_factory'
9
9
 
10
10
  require_relative '../mixins/inspector'
@@ -19,7 +19,7 @@ module GoodData
19
19
  #################################
20
20
  # Constants
21
21
  #################################
22
- DEFAULT_CONNECTION_IMPLEMENTATION = Connections::RestClientConnection
22
+ DEFAULT_CONNECTION_IMPLEMENTATION = GoodData::Rest::Connection
23
23
 
24
24
  #################################
25
25
  # Class variables
@@ -60,6 +60,11 @@ module GoodData
60
60
  # @param password [String] Password to be used for authentication
61
61
  # @return [GoodData::Rest::Client] Client
62
62
  def connect(username, password, opts = { :verify_ssl => true })
63
+ if username.nil? && password.nil?
64
+ username = ENV['GD_GEM_USER']
65
+ password = ENV['GD_GEM_PASSWORD']
66
+ end
67
+
63
68
  new_opts = opts.dup
64
69
  if username.is_a?(Hash) && username.key?(:sst_token)
65
70
  new_opts[:sst_token] = username[:sst_token]
@@ -83,7 +88,7 @@ module GoodData
83
88
 
84
89
  if client
85
90
  at_exit do
86
- # puts client.connection.stats_table if client && client.connection
91
+ puts client.connection.stats_table if client && client.connection && (GoodData.stats_on? || client.stats_on?)
87
92
  end
88
93
  end
89
94
 
@@ -104,18 +109,8 @@ module GoodData
104
109
  end
105
110
 
106
111
  # Retry block if exception thrown
107
- def retryable(options = {}, &_block)
108
- opts = { :tries => 1, :on => Exception }.merge(options)
109
-
110
- retry_exception, retries = opts[:on], opts[:tries]
111
-
112
- begin
113
- return yield
114
- rescue retry_exception
115
- retry if (retries -= 1) > 0
116
- end
117
-
118
- yield
112
+ def retryable(options = {}, &block)
113
+ GoodData::Rest::Connection.retryable(options, &block)
119
114
  end
120
115
 
121
116
  alias_method :client, :connection
@@ -145,7 +140,7 @@ module GoodData
145
140
  end
146
141
 
147
142
  def create_project(options = { title: 'Project', auth_token: ENV['GD_PROJECT_TOKEN'] })
148
- GoodData::Project.create(options.merge(client: self))
143
+ GoodData::Project.create({ client: self }.merge(options))
149
144
  end
150
145
 
151
146
  def create_project_from_blueprint(blueprint, options = {})
@@ -192,8 +187,24 @@ module GoodData
192
187
  nil
193
188
  end
194
189
 
195
- def user
196
- create(GoodData::Profile, @connection.user)
190
+ def user(id = nil)
191
+ if id
192
+ create(GoodData::Profile, get(id))
193
+ else
194
+ create(GoodData::Profile, @connection.user)
195
+ end
196
+ end
197
+
198
+ def stats_off
199
+ @stats = false
200
+ end
201
+
202
+ def stats_on
203
+ @stats = true
204
+ end
205
+
206
+ def stats_on? # rubocop:disable Style/TrivialAccessors
207
+ @stats
197
208
  end
198
209
 
199
210
  #######################
@@ -253,7 +264,7 @@ module GoodData
253
264
 
254
265
  while response.code == code
255
266
  sleep sleep_interval
256
- GoodData::Rest::Client.retryable(:tries => 3, :on => RestClient::InternalServerError) do
267
+ GoodData::Rest::Client.retryable(:tries => 3, :refresh_token => proc { connection.refresh_token }) do
257
268
  sleep sleep_interval
258
269
  response = get(link, :process => false)
259
270
  end
@@ -279,7 +290,7 @@ module GoodData
279
290
  response = get(link)
280
291
  while bl.call(response)
281
292
  sleep sleep_interval
282
- GoodData::Rest::Client.retryable(:tries => 3, :on => RestClient::InternalServerError) do
293
+ GoodData::Rest::Client.retryable(:tries => 3, :refresh_token => proc { connection.refresh_token }) do
283
294
  sleep sleep_interval
284
295
  response = get(link)
285
296
  end
@@ -318,7 +329,7 @@ module GoodData
318
329
  @connection.download source_relative_path, target_file_path, options
319
330
  end
320
331
 
321
- def download_from_user_webdav(source_relative_path, target_file_path, options = {})
332
+ def download_from_user_webdav(source_relative_path, target_file_path, options = { :client => GoodData.client, :project => project })
322
333
  download(source_relative_path, target_file_path, options.merge(
323
334
  :directory => options[:directory],
324
335
  :staging_url => get_user_webdav_url(options)
@@ -23,6 +23,16 @@ module GoodData
23
23
  :headers => DEFAULT_HEADERS
24
24
  }
25
25
 
26
+ RETRYABLE_ERRORS = [
27
+ RestClient::InternalServerError,
28
+ RestClient::RequestTimeout,
29
+ RestClient::MethodNotAllowed,
30
+ SystemCallError,
31
+ Timeout::Error
32
+ ]
33
+
34
+ RETRYABLE_ERRORS << Net::ReadTimeout if Net.const_defined?(:ReadTimeout)
35
+
26
36
  class << self
27
37
  def construct_login_payload(username, password)
28
38
  res = {
@@ -34,6 +44,36 @@ module GoodData
34
44
  }
35
45
  res
36
46
  end
47
+
48
+ # Retry block if exception thrown
49
+ def retryable(options = {}, &_block)
50
+ opts = { :tries => 1, :on => RETRYABLE_ERRORS }.merge(options)
51
+
52
+ retry_exception, retries = opts[:on], opts[:tries]
53
+
54
+ unless retry_exception.is_a?(Array)
55
+ retry_exception = [retry_exception]
56
+ end
57
+
58
+ retry_time = 1
59
+ begin
60
+ return yield
61
+ rescue RestClient::Forbidden => e # , RestClient::Unauthorized => e
62
+ raise e unless options[:refresh_token]
63
+ options[:refresh_token].call
64
+ retry if (retries -= 1) > 0
65
+ rescue RestClient::TooManyRequests
66
+ GoodData.logger.warn "Too many requests, retrying in #{retry_time} seconds"
67
+ sleep retry_time
68
+ retry_time *= 1.5
69
+ retry
70
+ rescue *retry_exception => e
71
+ GoodData.logger.warn e.inspect
72
+ retry if (retries -= 1) > 0
73
+ end
74
+
75
+ yield
76
+ end
37
77
  end
38
78
 
39
79
  attr_reader :cookies
@@ -41,17 +81,39 @@ module GoodData
41
81
  attr_reader :user
42
82
 
43
83
  def initialize(opts)
84
+ @stats = {}
85
+ @opts = opts
86
+
87
+ @headers = DEFAULT_HEADERS.dup
44
88
  @user = nil
89
+ @server = nil
45
90
 
46
- @stats = {}
47
91
  @opts = opts
92
+ headers = opts[:headers] || {}
93
+ @headers.merge! headers
48
94
 
49
95
  # Initialize cookies
50
96
  reset_cookies!
97
+
98
+ @at_exit_handler_installed = nil
51
99
  end
52
100
 
53
101
  # Connect using username and password
54
102
  def connect(username, password, options = {})
103
+ server = options[:server] || DEFAULT_URL
104
+ @server = RestClient::Resource.new server, DEFAULT_LOGIN_PAYLOAD
105
+
106
+ # Install at_exit handler first
107
+ unless @at_exit_handler_installed
108
+ begin
109
+ at_exit { disconnect if @user }
110
+ rescue RestClient::Unauthorized
111
+ GoodData.logger.info 'Already logged out'
112
+ ensure
113
+ @at_exit_handler_installed = true
114
+ end
115
+ end
116
+
55
117
  # Reset old cookies first
56
118
  if options[:sst_token]
57
119
  merge_cookies!('GDCAuthSST' => options[:sst_token])
@@ -62,8 +124,8 @@ module GoodData
62
124
  credentials = Connection.construct_login_payload(username, password)
63
125
  @auth = post(LOGIN_PATH, credentials, :dont_reauth => true)['userLogin']
64
126
 
65
- @user = get(@auth['profile'])
66
127
  refresh_token :dont_reauth => true
128
+ @user = get(@auth['profile'])
67
129
  end
68
130
  end
69
131
 
@@ -71,7 +133,12 @@ module GoodData
71
133
  def disconnect
72
134
  # TODO: Wrap somehow
73
135
  url = @auth['state']
74
- delete url if url
136
+
137
+ begin
138
+ delete url if url
139
+ rescue RestClient::Unauthorized
140
+ GoodData.logger.info 'Already disconnected'
141
+ end
75
142
 
76
143
  @auth = nil
77
144
  @server = nil
@@ -80,6 +147,72 @@ module GoodData
80
147
  reset_cookies!
81
148
  end
82
149
 
150
+ def download(what, where, options = {})
151
+ # handle the path (directory) given in what
152
+ ilast_slash = what.rindex('/')
153
+ if ilast_slash.nil?
154
+ what_dir = ''
155
+ else
156
+ # take the directory from the path
157
+ what_dir = what[0..ilast_slash - 1]
158
+ # take the filename from the path
159
+ what = what[ilast_slash + 1..-1]
160
+ end
161
+
162
+ option_dir = options[:directory] || ''
163
+ option_dir = option_dir[0..-2] if option_dir[-1] == '/'
164
+
165
+ # join the otion dir with the what_dir
166
+ # [option dir empty, what dir empty] => the joined dir
167
+ dir_hash = {
168
+ [true, true] => '',
169
+ [true, false] => what_dir,
170
+ [false, true] => option_dir,
171
+ [false, false] => "#{what_dir}/#{option_dir}"
172
+ }
173
+ dir = dir_hash[[option_dir.empty?, what_dir.empty?]]
174
+
175
+ staging_uri = options[:staging_url].to_s
176
+
177
+ base_url = dir.empty? ? staging_uri : URI.join(staging_uri, "#{dir}/").to_s
178
+ url = URI.join(base_url, CGI.escape(what)).to_s
179
+
180
+ b = proc do
181
+ raw = {
182
+ :headers => {
183
+ :user_agent => GoodData.gem_version_string
184
+ },
185
+ :method => :get,
186
+ :url => url
187
+ }.merge(cookies)
188
+
189
+ if where.is_a?(IO)
190
+ RestClient::Request.execute(raw) do |chunk, _x, response|
191
+ if response.code.to_s != '200'
192
+ fail ArgumentError, "Error downloading #{url}. Got response: #{response.code} #{response} #{response.body}"
193
+ end
194
+ where.write chunk
195
+ end
196
+ else
197
+ # Assume it is a string or file
198
+ File.open(where, 'w') do |f|
199
+ RestClient::Request.execute(raw) do |chunk, _x, response|
200
+ if response.code.to_s != '200'
201
+ fail ArgumentError, "Error downloading #{url}. Got response: #{response.code} #{response} #{response.body}"
202
+ end
203
+ f.write chunk
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ res = nil
210
+ GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
211
+ res = b.call
212
+ end
213
+ res
214
+ end
215
+
83
216
  def refresh_token(_options = {})
84
217
  begin # rubocop:disable RedundantBegin
85
218
  get TOKEN_PATH, :dont_reauth => true # avoid infinite loop GET fails with 401
@@ -99,29 +232,47 @@ module GoodData
99
232
  # HTTP DELETE
100
233
  #
101
234
  # @param uri [String] Target URI
102
- def delete(uri, _options = {})
103
- fail NotImplementedError "DELETE #{uri}"
235
+ def delete(uri, options = {})
236
+ GoodData.logger.debug "DELETE: #{@server.url}#{uri}"
237
+ profile "DELETE #{uri}" do
238
+ b = proc { @server[uri].delete cookies }
239
+ process_response(options, &b)
240
+ end
104
241
  end
105
242
 
106
243
  # HTTP GET
107
244
  #
108
245
  # @param uri [String] Target URI
109
- def get(uri, _options = {})
110
- fail NotImplementedError "GET #{uri}"
246
+ def get(uri, options = {}, &user_block)
247
+ GoodData.logger.debug "GET: #{@server.url}#{uri}"
248
+ profile "GET #{uri}" do
249
+ b = proc { @server[uri].get(cookies, &user_block) }
250
+ process_response(options, &b)
251
+ end
111
252
  end
112
253
 
113
254
  # HTTP PUT
114
255
  #
115
256
  # @param uri [String] Target URI
116
- def put(uri, _data, _options = {})
117
- fail NotImplementedError "PUT #{uri}"
257
+ def put(uri, data, options = {})
258
+ payload = data.is_a?(Hash) ? data.to_json : data
259
+ GoodData.logger.debug "PUT: #{@server.url}#{uri}, #{scrub_params(data, [:password, :login, :authorizationToken])}"
260
+ profile "PUT #{uri}" do
261
+ b = proc { @server[uri].put payload, cookies }
262
+ process_response(options, &b)
263
+ end
118
264
  end
119
265
 
120
266
  # HTTP POST
121
267
  #
122
268
  # @param uri [String] Target URI
123
- def post(uri, _data, _options = {})
124
- fail NotImplementedError "POST #{uri}"
269
+ def post(uri, data, options = {})
270
+ GoodData.logger.debug "POST: #{@server.url}#{uri}, #{scrub_params(data, [:password, :login, :authorizationToken])}"
271
+ profile "POST #{uri}" do
272
+ payload = data.is_a?(Hash) ? data.to_json : data
273
+ b = proc { @server[uri].post payload, cookies }
274
+ process_response(options, &b)
275
+ end
125
276
  end
126
277
 
127
278
  # Reader method for SST token
@@ -155,12 +306,133 @@ module GoodData
155
306
  cookies[:cookies]['GDCAuthTT']
156
307
  end
157
308
 
309
+ # Uploads a file to GoodData server
310
+ def upload(file, options = {})
311
+ def do_stream_file(uri, filename, _options = {})
312
+ puts "uploading the file #{uri}"
313
+
314
+ to_upload = File.new(filename)
315
+ cookies_str = cookies[:cookies].map { |cookie| "#{cookie[0]}=#{cookie[1]}" }.join(';')
316
+ req = Net::HTTP::Put.new(uri.path, 'User-Agent' => GoodData.gem_version_string, 'Cookie' => cookies_str)
317
+ req.content_length = to_upload.size
318
+ req.body_stream = to_upload
319
+ http = Net::HTTP.new(uri.host, uri.port)
320
+ http.use_ssl = true
321
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
322
+
323
+ response = nil
324
+ GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
325
+ response = http.start { |client| client.request(req) }
326
+ end
327
+ response
328
+ end
329
+
330
+ def webdav_dir_exists?(url)
331
+ method = :get
332
+ GoodData.logger.debug "#{method}: #{url}"
333
+
334
+ b = proc do
335
+ raw = {
336
+ :method => method,
337
+ :url => url,
338
+ :headers => @headers
339
+ }
340
+ begin
341
+ RestClient::Request.execute(raw.merge(cookies))
342
+ rescue RestClient::Exception => e
343
+ false if e.http_code == 404
344
+ end
345
+ end
346
+
347
+ res = nil
348
+ GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
349
+ res = b.call
350
+ end
351
+ res
352
+ end
353
+
354
+ def create_webdav_dir_if_needed(url)
355
+ return if webdav_dir_exists?(url)
356
+
357
+ method = :mkcol
358
+ GoodData.logger.debug "#{method}: #{url}"
359
+ b = proc do
360
+ raw = {
361
+ :method => method,
362
+ :url => url,
363
+ :headers => @headers
364
+ }.merge(cookies)
365
+ RestClient::Request.execute(raw)
366
+ end
367
+
368
+ GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
369
+ b.call
370
+ end
371
+ end
372
+
373
+ dir = options[:directory] || ''
374
+ staging_uri = options[:staging_url].to_s
375
+ url = dir.empty? ? staging_uri : URI.join(staging_uri, "#{dir}/").to_s
376
+
377
+ # Make a directory, if needed
378
+ create_webdav_dir_if_needed url unless dir.empty?
379
+
380
+ webdav_filename = options[:filename] || File.basename(file)
381
+ do_stream_file URI.join(url, CGI.escape(webdav_filename)), file
382
+ end
383
+
158
384
  private
159
385
 
160
386
  def merge_cookies!(cookies)
161
387
  @cookies[:cookies].merge! cookies
162
388
  end
163
389
 
390
+ def process_response(options = {}, &block)
391
+ # begin
392
+ # # Simply try again when ConnectionReset, ConnectionRefused etc.. (see e.g. MSF-7591)
393
+ # response = GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => Proc.new { refresh_token }) do
394
+ # block.call
395
+ # end
396
+ # rescue RestClient::Unauthorized
397
+ # raise $ERROR_INFO if options[:dont_reauth]
398
+ # GoodData::Rest::Connection.retryable(:tries => 2) do
399
+ # refresh_token
400
+ # response = block.call
401
+ # end
402
+ # end
403
+
404
+ response = GoodData::Rest::Connection.retryable(:tries => 2, :refresh_token => proc { refresh_token }) do
405
+ block.call
406
+ end
407
+
408
+ merge_cookies! response.cookies
409
+ content_type = response.headers[:content_type]
410
+ return response if options[:process] == false
411
+
412
+ if content_type == 'application/json' || content_type == 'application/json;charset=UTF-8'
413
+ result = response.to_str == '""' ? {} : MultiJson.load(response.to_str)
414
+ GoodData.logger.debug "Request ID: #{response.headers[:x_gdc_request]} - Response: #{result.inspect}"
415
+ elsif ['text/plain;charset=UTF-8', 'text/plain; charset=UTF-8', 'text/plain'].include?(content_type)
416
+ result = response
417
+ GoodData.logger.debug 'Response: plain text'
418
+ elsif content_type == 'application/zip'
419
+ result = response
420
+ GoodData.logger.debug 'Response: a zipped stream'
421
+ elsif response.headers[:content_length].to_s == '0'
422
+ result = nil
423
+ GoodData.logger.debug 'Response: Empty response possibly 204'
424
+ elsif response.code == 204
425
+ result = nil
426
+ GoodData.logger.debug 'Response: 204 no content'
427
+ else
428
+ fail "Unsupported response content type '%s':\n%s" % [content_type, response.to_str[0..127]]
429
+ end
430
+ result
431
+ rescue RestClient::Exception => e
432
+ GoodData.logger.debug "Response: #{e.response}"
433
+ raise $ERROR_INFO
434
+ end
435
+
164
436
  def profile(title, &block)
165
437
  t1 = Time.now
166
438
  res = block.call