4me-sdk 1.1.8 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aba8de45bcc385f1f8ffedfce680f58cb5c73865510798712d7d8c382ecbd9bf
4
- data.tar.gz: 1ffb444710f94ad590aa4943589465e028ad7cf1957bd5546fd93fe158871c6e
3
+ metadata.gz: dc85cfa0c6b08a248805e24e37b4fe0cde152c64d42443b72ca8db4e5cf2799a
4
+ data.tar.gz: ebfe8f4d1e32e791ef5d109ef6934aa3fa585a60df8cd1f4f000073993cc9a2f
5
5
  SHA512:
6
- metadata.gz: bdd2c6e55c547a2b13ca893a73e3167d77adee143e53e396b48d8712cfb8d7e148f0f3b10090c3b20691e22b20ddad4a1593d6f8e374880a98c9f8b71abfbe85
7
- data.tar.gz: d63bc178ea462a8b4691ad2d63c25ca48ae5735820d398047dfe98ff450be1a6d3f6c8aa8e27c30829afb9753b5213a6f55c0539d1ba03f134908ea8a59ae4f3
6
+ metadata.gz: e05769acff36f8c0ffc6758d4078217b4af13cd969814ee85699d0e84951c6b9d34d6d4b2d7fb0fddb2577a2a03b4aeda3b7c687d0ec62916ef8e712ce5224cc
7
+ data.tar.gz: 6cac609bb11b34d97086e701701d7f664ca24500cca943a948e7ce42d7650e2dd2c8f14a0a348dd6d0b2295c90257d1a39411ae0f2e7a8a67202396edf8dc31b
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency 'bundler', '~> 1'
35
35
  spec.add_development_dependency 'rake', '~> 12'
36
36
  spec.add_development_dependency 'rspec', '~> 3.3'
37
- spec.add_development_dependency 'webmock', '~> 2'
37
+ spec.add_development_dependency 'webmock', '~> 3'
38
38
  spec.add_development_dependency 'simplecov', '~> 0'
39
39
 
40
40
  end
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- 4me-sdk (1.1.8)
4
+ 4me-sdk (1.2.0)
5
5
  activesupport (>= 4.2)
6
6
  gem_config (>= 0.3)
7
7
  mime-types (>= 3.0)
@@ -14,23 +14,22 @@ GEM
14
14
  i18n (>= 0.7, < 2)
15
15
  minitest (~> 5.1)
16
16
  tzinfo (~> 1.1)
17
- addressable (2.5.2)
18
- public_suffix (>= 2.0.2, < 4.0)
17
+ addressable (2.7.0)
18
+ public_suffix (>= 2.0.2, < 5.0)
19
19
  concurrent-ruby (1.1.5)
20
- crack (0.4.3)
21
- safe_yaml (~> 1.0.0)
20
+ crack (0.4.4)
22
21
  diff-lcs (1.3)
23
22
  docile (1.3.1)
24
23
  gem_config (0.3.1)
25
- hashdiff (0.3.7)
24
+ hashdiff (1.0.1)
26
25
  i18n (1.5.1)
27
26
  concurrent-ruby (~> 1.0)
28
27
  json (2.1.0)
29
28
  mime-types (3.2.2)
30
29
  mime-types-data (~> 3.2015)
31
30
  mime-types-data (3.2019.0331)
32
- minitest (5.11.3)
33
- public_suffix (3.0.3)
31
+ minitest (5.13.0)
32
+ public_suffix (4.0.6)
34
33
  rake (12.3.1)
35
34
  rspec (3.8.0)
36
35
  rspec-core (~> 3.8.0)
@@ -45,7 +44,6 @@ GEM
45
44
  diff-lcs (>= 1.2.0, < 2.0)
46
45
  rspec-support (~> 3.8.0)
47
46
  rspec-support (3.8.0)
48
- safe_yaml (1.0.4)
49
47
  simplecov (0.16.1)
50
48
  docile (~> 1.1)
51
49
  json (>= 1.8, < 3)
@@ -54,10 +52,10 @@ GEM
54
52
  thread_safe (0.3.6)
55
53
  tzinfo (1.2.5)
56
54
  thread_safe (~> 0.1)
57
- webmock (2.3.2)
55
+ webmock (3.9.1)
58
56
  addressable (>= 2.3.6)
59
57
  crack (>= 0.3.2)
60
- hashdiff
58
+ hashdiff (>= 0.4.0, < 2.0.0)
61
59
 
62
60
  PLATFORMS
63
61
  ruby
@@ -68,7 +66,7 @@ DEPENDENCIES
68
66
  rake (~> 12)
69
67
  rspec (~> 3.3)
70
68
  simplecov (~> 0)
71
- webmock (~> 2)
69
+ webmock (~> 3)
72
70
 
73
71
  BUNDLED WITH
74
72
  1.17.3
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Sdk4me::Client
2
2
 
3
- Client for accessing the [4me REST API](http://developer.4me.com/v1/)
3
+ Client for accessing the [4me REST API](https://developer.4me.com/v1/)
4
4
 
5
5
  ## Installation
6
6
 
@@ -22,7 +22,7 @@ Or install it yourself as:
22
22
 
23
23
  ```
24
24
  Sdk4me.configure do |config|
25
- config.api_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
25
+ config.access_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
26
26
  config.account = 'my-sandbox'
27
27
  config.logger = Rails.logger
28
28
  ...
@@ -32,17 +32,18 @@ end
32
32
  All options available:
33
33
 
34
34
  * _logger_: The [Ruby Logger](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html) instance, default: `Logger.new(STDOUT)`
35
- * _host_: The [4me API host](http://developer.4me.com/v1/#service-url), default: 'https://api.4me.com'
36
- * _api_version_: The [4me API version](http://developer.4me.com/v1/#service-url), default: 'v1'
37
- * _api_token_: (**required**) The [4me API token](http://developer.4me.com/v1/#api-tokens)
38
- * _account_: Specify a [different account](http://developer.4me.com/v1/#multiple-accounts) to work with
39
- * _source_: The [source](http://developer.4me.com/v1/general/source/) used when creating new records
35
+ * _host_: The [4me API host](https://developer.4me.com/v1/#service-url), default: 'https://api.4me.com'
36
+ * _api_version_: The [4me API version](https://developer.4me.com/v1/#service-url), default: 'v1'
37
+ * _access_token_: (**required**) The [4me access token](https://developer.4me.com/v1/#authentication)
38
+ * _api_token_: (**deprecated**) The [4me API token](https://developer.4me.com/v1/#api-tokens)
39
+ * _account_: Specify a [different account](https://developer.4me.com/v1/#multiple-accounts) to work with
40
+ * _source_: The [source](https://developer.4me.com/v1/general/source/) used when creating new records
40
41
  * _max_retry_time_: maximum nr of seconds to retry a request on a failed response (default = 300 = 5 minutes)<br/>
41
42
  The sleep time between retries starts at 2 seconds and doubles after each retry, i.e.
42
43
  2, 6, 18, 54, 162, 486, 1458, ... seconds.<br/>
43
44
  Set to 0 to prevent retries.
44
45
  * _read_timeout_: [HTTP read timeout](http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-read_timeout-3D) in seconds (default = 25)
45
- * _block_at_rate_limit_: Set to `true` to block the request until the [rate limit](http://developer.4me.com/v1/#rate-limiting) is lifted, default: `true`<br/>
46
+ * _block_at_rate_limit_: Set to `true` to block the request until the [rate limit](https://developer.4me.com/v1/#rate-limiting) is lifted, default: `true`<br/>
46
47
  The `Retry-After` header is used to compute when the retry should be performed. If that moment is later than the _max_throttle_time_ the request will not be blocked and the throttled response is returned.
47
48
  * _max_throttle_time_: maximum nr of seconds to retry a request on a rate limiter (default = 3660 = 1 hour and 1 minute)<br/>
48
49
  * _proxy_host_: Define in case HTTP traffic needs to go through a proxy
@@ -70,7 +71,7 @@ Minimal example:
70
71
  ```
71
72
  require 'sdk4me/client'
72
73
 
73
- client = Sdk4me::Client.new(api_token: '3a4e4590179263839...')
74
+ client = Sdk4me::Client.new(access_token: '3a4e4590179263839...')
74
75
  response = client.get('me')
75
76
  puts response[:primary_email]
76
77
  ```
@@ -84,7 +85,7 @@ response = Sdk4me::Client.new.get('organizations/4321')
84
85
  puts response[:name]
85
86
  ```
86
87
 
87
- By default this call will return all [fields](http://developer.4me.com/v1/organizations/#fields) of the Organization.
88
+ By default this call will return all [fields](https://developer.4me.com/v1/organizations/#fields) of the Organization.
88
89
 
89
90
  The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
90
91
  ```
@@ -105,8 +106,8 @@ end
105
106
  puts "Found #{count} organizations"
106
107
  ```
107
108
 
108
- By default this call will return all [collection fields](http://developer.4me.com/v1/organizations/#collection-fields) for each Organization.
109
- For more fields, check out the [field selection](http://developer.4me.com/v1/general/field_selection/#collection-of-resources) documentation.
109
+ By default this call will return all [collection fields](https://developer.4me.com/v1/organizations/#collection-fields) for each Organization.
110
+ For more fields, check out the [field selection](https://developer.4me.com/v1/general/field_selection/#collection-of-resources) documentation.
110
111
 
111
112
  The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
112
113
  ```
@@ -123,7 +124,7 @@ Note that an `Sdk4me::Exception` could be thrown in case one of the API requests
123
124
 
124
125
  The `each` method [described above](#browse-through-a-collection-of-records) is the preferred way to work with collections of data.
125
126
 
126
- If you really want to [paginate](http://developer.4me.com/v1/general/pagination/) yourself, the `get` method is your friend.
127
+ If you really want to [paginate](https://developer.4me.com/v1/general/pagination/) yourself, the `get` method is your friend.
127
128
 
128
129
  ```
129
130
  @client = Sdk4me::Client.new
@@ -141,8 +142,8 @@ next_page = @client.get(response.pagination_link(:next))
141
142
  last_page = @client.get(response.pagination_link(:last))
142
143
  ```
143
144
 
144
- By default this call will return all [collection fields](http://developer.4me.com/v1/organizations/#collection-fields) for each Organization.
145
- For more fields, check out the [field selection](http://developer.4me.com/v1/general/field_selection/#collection-of-resources) documentation.
145
+ By default this call will return all [collection fields](https://developer.4me.com/v1/organizations/#collection-fields) for each Organization.
146
+ For more fields, check out the [field selection](https://developer.4me.com/v1/general/field_selection/#collection-of-resources) documentation.
146
147
 
147
148
  The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
148
149
  ```
@@ -243,7 +244,7 @@ end
243
244
 
244
245
  ### Importing CSV files
245
246
 
246
- 4me also provides an [Import API](http://developer.4me.com/v1/import/). The 4me SDK Client can be used to upload files to that API.
247
+ 4me also provides an [Import API](https://developer.4me.com/v1/import/). The 4me SDK Client can be used to upload files to that API.
247
248
 
248
249
  ```
249
250
  response = Sdk4me::Client.new.import('\tmp\people.csv', 'people')
@@ -255,9 +256,9 @@ end
255
256
 
256
257
  ```
257
258
 
258
- The second argument contains the [import type](http://developer.4me.com/v1/import/#parameters).
259
+ The second argument contains the [import type](https://developer.4me.com/v1/import/#parameters).
259
260
 
260
- It is also possible to [monitor the progress](http://developer.4me.com/v1/import/#import-progress) of the import and block until the import is complete. In that case you will need to add some exception handling to your code.
261
+ It is also possible to [monitor the progress](https://developer.4me.com/v1/import/#import-progress) of the import and block until the import is complete. In that case you will need to add some exception handling to your code.
261
262
 
262
263
  ```
263
264
  begin
@@ -277,7 +278,7 @@ Note that blocking for the import to finish is required when you import multiple
277
278
 
278
279
  ### Exporting CSV files
279
280
 
280
- 4me also provides an [Export API](http://developer.4me.com/v1/export/). The 4me SDK Client can be used to download (zipped) CSV files using that API.
281
+ 4me also provides an [Export API](https://developer.4me.com/v1/export/). The 4me SDK Client can be used to download (zipped) CSV files using that API.
281
282
 
282
283
  ```
283
284
  response = Sdk4me::Client.new.export(['people', 'people_contact_details'], DateTime.new(2012,03,30,23,00,00))
@@ -289,10 +290,10 @@ end
289
290
 
290
291
  ```
291
292
 
292
- The first argument contains the [export types](http://developer.4me.com/v1/export/#parameters).
293
+ The first argument contains the [export types](https://developer.4me.com/v1/export/#parameters).
293
294
  The second argument is optional and limits the export to all changed records since the given time.
294
295
 
295
- It is also possible to [monitor the progress](http://developer.4me.com/v1/export/#export-progress) of the export and block until the export is complete. In that case you will need to add some exception handling to your code.
296
+ It is also possible to [monitor the progress](https://developer.4me.com/v1/export/#export-progress) of the export and block until the export is complete. In that case you will need to add some exception handling to your code.
296
297
 
297
298
  ```
298
299
  require 'open-uri'
@@ -314,7 +315,7 @@ Note that blocking for the export to finish is recommended as you will get direc
314
315
 
315
316
  ### Blocking
316
317
 
317
- When the currently used API token hits the [4me rate limiter](http://developer.4me.com/v1/#rate-limiting) a HTTP 429 response is returned that specifies after how many seconds the rate limit will be lifted.
318
+ When the currently used API token hits the [4me rate limiter](https://developer.4me.com/v1/#rate-limiting) a HTTP 429 response is returned that specifies after how many seconds the rate limit will be lifted.
318
319
 
319
320
  If that time lies within the _max_throttle_time_ the 4me SDK Client will wait and retry the action, if not, the throttled response will be returned. You can verify if a response was throttled using:
320
321
  ```
@@ -336,7 +337,7 @@ When exporting translations, the _locale_ parameter is required:
336
337
 
337
338
  ### Exception handling
338
339
 
339
- The standard methods `get`, `post`, `put` and `delete` will always return a Response with an [error message](http://developer.4me.com/v1/#http-status-codes) in case something went wrong.
340
+ The standard methods `get`, `post`, `put` and `delete` will always return a Response with an [error message](https://developer.4me.com/v1/#http-status-codes) in case something went wrong.
340
341
 
341
342
  By calling `response.valid?` you will know if the action succeeded or not, and `response.message` provides additinal information in case the response was invalid.
342
343
 
@@ -9,6 +9,7 @@ module Sdk4me
9
9
 
10
10
  has :host, classes: String, default: 'https://api.4me.com'
11
11
  has :api_version, values: ['v1'], default: 'v1'
12
+ has :access_token, classes: String
12
13
  has :api_token, classes: String
13
14
 
14
15
  has :account, classes: String
@@ -27,7 +27,7 @@ module Sdk4me
27
27
  #
28
28
  # Shared configuration for all 4me SDK Clients:
29
29
  # Sdk4me.configure do |config|
30
- # config.api_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
30
+ # config.access_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
31
31
  # config.account = 'my-sandbox'
32
32
  # ...
33
33
  # end
@@ -39,11 +39,11 @@ module Sdk4me
39
39
  # - logger: The Ruby Logger instance, default: Logger.new(STDOUT)
40
40
  # - host: The 4me API host, default: 'https://api.4me.com'
41
41
  # - api_version: The 4me API version, default: 'v1'
42
- # - api_token: *required* The 4me API token
42
+ # - access_token: *required* The 4me access token
43
43
  # - account: Specify a different (trusted) account to work with
44
- # @see http://developer.4me.com/v1/#multiple-accounts
44
+ # @see https://developer.4me.com/v1/#multiple-accounts
45
45
  # - source: The Source used when creating new records
46
- # @see http://developer.4me.com/v1/general/source/
46
+ # @see https://developer.4me.com/v1/general/source/
47
47
  #
48
48
  # - max_retry_time: maximum nr of seconds to wait for server to respond (default = 5400 = 1.5 hours)
49
49
  # the sleep time between retries starts at 2 seconds and doubles after each retry
@@ -51,7 +51,7 @@ module Sdk4me
51
51
  # one retry will always be performed unless you set the value to -1
52
52
  # - read_timeout: HTTP GET read timeout in seconds (default = 25)
53
53
  # - block_at_rate_limit: Set to +true+ to block the request until the rate limit is lifted, default: +false+
54
- # @see http://developer.4me.com/v1/#rate-limiting
54
+ # @see https://developer.4me.com/v1/#rate-limiting
55
55
  #
56
56
  # - proxy_host: Define in case HTTP traffic needs to go through a proxy
57
57
  # - proxy_port: Port of the proxy, defaults to 8080
@@ -59,12 +59,19 @@ module Sdk4me
59
59
  # - proxy_password: Proxy password
60
60
  def initialize(options = {})
61
61
  @options = Sdk4me.configuration.current.merge(options)
62
- [:host, :api_version, :api_token].each do |required_option|
62
+ [:host, :api_version].each do |required_option|
63
63
  raise ::Sdk4me::Exception.new("Missing required configuration option #{required_option}") if option(required_option).blank?
64
64
  end
65
+ @logger = @options[:logger]
65
66
  @ssl, @domain, @port = ssl_domain_port_path(option(:host))
67
+ unless option(:access_token).present?
68
+ if option(:api_token).blank?
69
+ raise ::Sdk4me::Exception.new("Missing required configuration option access_token")
70
+ else
71
+ @logger.info('Use of api_token is deprecated, consider switching to access_token instead.')
72
+ end
73
+ end
66
74
  @ssl_verify_none = options[:ssl_verify_none]
67
- @logger = @options[:logger]
68
75
  end
69
76
 
70
77
  # Retrieve an option
@@ -211,8 +218,12 @@ module Sdk4me
211
218
  def expand_header(header = {})
212
219
  header = DEFAULT_HEADER.merge(header)
213
220
  header['X-4me-Account'] = option(:account) if option(:account)
214
- token_and_password = option(:api_token).include?(':') ? option(:api_token) : "#{option(:api_token)}:x"
215
- header['AUTHORIZATION'] = 'Basic ' + [token_and_password].pack('m*').gsub(/\s/, '')
221
+ if option(:access_token).present?
222
+ header['AUTHORIZATION'] = 'Bearer ' + option(:access_token)
223
+ else
224
+ token_and_password = option(:api_token).include?(':') ? option(:api_token) : "#{option(:api_token)}:x"
225
+ header['AUTHORIZATION'] = 'Basic ' + [token_and_password].pack('m*').gsub(/\s/, '')
226
+ end
216
227
  if option(:source)
217
228
  header['X-4me-Source'] = option(:source)
218
229
  header['HTTP_USER_AGENT'] = option(:source)
@@ -1,5 +1,5 @@
1
1
  module Sdk4me
2
2
  class Client
3
- VERSION = '1.1.8'
3
+ VERSION = '1.2.0'
4
4
  end
5
5
  end
@@ -2,243 +2,262 @@ require 'spec_helper'
2
2
 
3
3
  describe Sdk4me::Attachments do
4
4
 
5
- before(:each) do
6
- @client = Sdk4me::Client.new(api_token: 'secret', max_retry_time: -1)
7
- @attachments = Sdk4me::Attachments.new(@client)
8
- end
9
-
10
- context 'upload_attachments!' do
11
- context 'normal' do
12
- it 'should not do anything when no :attachments are present' do
13
- expect(@attachments.upload_attachments!('/requests', {status: :in_progress})).to be_nil
14
- end
15
-
16
- it 'should not do anything when :attachments is nil' do
17
- expect(@attachments.upload_attachments!('/requests', {attachments: nil})).to be_nil
18
- end
19
-
20
- it 'should not do anything when :attachments is empty' do
21
- expect(@attachments.upload_attachments!('/requests', {attachments: []})).to be_nil
22
- expect(@attachments.upload_attachments!('/requests', {attachments: [nil]})).to be_nil
23
- end
24
-
25
- it 'should show a error if no attachment may be uploaded' do
26
- stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
27
- expect_log('Attachments not allowed for /sites/1', :error)
28
- expect(@attachments.upload_attachments!('/sites/1', {attachments: ['file1.png']})).to be_nil
29
- end
30
-
31
- it 'should raise an exception if no attachment may be uploaded' do
32
- stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
33
- message = 'Attachments not allowed for /sites/1'
34
- expect{ @attachments.upload_attachments!('/sites/1', {attachments: ['file1.png'], attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
35
- end
36
-
37
- it 'should add /new to the path for new records' do
38
- stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {missing: 'storage'}.to_json)
39
- expect_log('Attachments not allowed for /sites', :error)
40
- expect(@attachments.upload_attachments!('/sites', {attachments: ['file1.png']})).to be_nil
41
- end
42
-
43
- [ [:requests, :note],
44
- [:problems, :note],
45
- [:contracts, :remarks],
46
- [:cis, :remarks],
47
- [:flsas, :remarks],
48
- [:slas, :remarks],
49
- [:service_instances, :remarks],
50
- [:service_offerings, :summary],
51
- [:any_other_model, :note]].each do |model, attribute|
52
-
53
- it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
54
- stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
55
- expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ 'uploaded file1.png' }
56
- expect(@attachments).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ 'uploaded file2.zip' }
57
- data = {leave: 'me alone', attachments: %w(file1.png file2.zip)}
58
- @attachments.upload_attachments!("/#{model}", data)
59
- expect(data[:attachments]).to be_nil
60
- expect(data[:leave]).to eq('me alone')
61
- expect(data[:"#{attribute}_attachments"]).to eq(['uploaded file1.png', 'uploaded file2.zip'].to_json)
62
- end
63
- end
64
-
65
- it 'should set raise_exception flag to true when :attachments_exception is set' do
66
- stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
67
- expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ 'uploaded file1.png' }
68
- data = {leave: 'me alone', attachments: 'file1.png', attachments_exception: true}
69
- @attachments.upload_attachments!('/requests', data)
70
- expect(data[:attachments]).to be_nil
71
- expect(data[:attachments_exception]).to be_nil
72
- expect(data[:leave]).to eq('me alone')
73
- expect(data[:note_attachments]).to eq(['uploaded file1.png'].to_json)
74
- end
75
- end
76
-
77
- context 'inline' do
78
- it 'should not do anything when no [attachment:...] is present in the note' do
79
- expect(@attachments.upload_attachments!('/requests', {note: '[attachmen:/type]'})).to be_nil
80
- end
81
-
82
- it 'should not do anything when attachment is empty' do
83
- expect(@attachments.upload_attachments!('/requests', {note: '[attachment:]'})).to be_nil
84
- end
85
-
86
- it 'should show a error if no attachment may be uploaded' do
87
- stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
88
- expect_log('Attachments not allowed for /sites/1', :error)
89
- expect(@attachments.upload_attachments!('/sites/1', {note: '[attachment:file1.png]'})).to be_nil
90
- end
91
-
92
- it 'should raise an exception if no attachment may be uploaded' do
93
- stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
94
- message = 'Attachments not allowed for /sites/1'
95
- expect{ @attachments.upload_attachments!('/sites/1', {note: '[attachment:file1.png]', attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
96
- end
97
-
98
- it 'should add /new to the path for new records' do
99
- stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {missing: 'storage'}.to_json)
100
- expect_log('Attachments not allowed for /sites', :error)
101
- expect(@attachments.upload_attachments!('/sites', {note: '[attachment:file1.png]'})).to be_nil
102
- end
103
-
104
- [ [:requests, :note],
105
- [:problems, :note],
106
- [:contracts, :remarks],
107
- [:cis, :remarks],
108
- [:flsas, :remarks],
109
- [:slas, :remarks],
110
- [:service_instances, :remarks],
111
- [:service_offerings, :summary],
112
- [:any_other_model, :note]].each do |model, attribute|
113
-
114
- it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
115
- stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
116
- expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ {key: 'uploaded file1.png'} }
117
- expect(@attachments).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ {key: 'uploaded file2.zip'} }
118
- data = {leave: 'me alone', attribute => '[attachment:file1.png] and [attachment:file2.zip]'}
119
- @attachments.upload_attachments!("/#{model}", data)
120
- expect(data[:attachments]).to be_nil
121
- expect(data[:leave]).to eq('me alone')
122
- expect(data[:"#{attribute}_attachments"]).to eq([{key: 'uploaded file1.png', inline: true}, {key: 'uploaded file2.zip', inline: true}].to_json)
123
- expect(data[:"#{attribute}"]).to eq('![](uploaded file1.png) and ![](uploaded file2.zip)')
124
- end
125
- end
126
-
127
- it 'should set raise_exception flag to true when :attachments_exception is set' do
128
- stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
129
- expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ {key: 'uploaded file1.png'} }
130
- data = {leave: 'me alone', note: '[attachment:file1.png]', attachments_exception: true}
131
- @attachments.upload_attachments!('/requests', data)
132
- expect(data[:attachments]).to be_nil
133
- expect(data[:attachments_exception]).to be_nil
134
- expect(data[:leave]).to eq('me alone')
135
- expect(data[:note_attachments]).to eq([{key: 'uploaded file1.png', inline: true}].to_json)
136
- expect(data[:note]).to eq('![](uploaded file1.png)')
137
- end
5
+ def attachments(authentication)
6
+ (@attachments ||= {})[authentication] ||= begin
7
+ client = if authentication == :api_token
8
+ Sdk4me::Client.new(api_token: 'secret', max_retry_time: -1)
9
+ else
10
+ Sdk4me::Client.new(access_token: 'secret', max_retry_time: -1)
11
+ end
12
+ Sdk4me::Attachments.new(client)
138
13
  end
139
-
140
14
  end
141
15
 
142
- context 'upload_attachment' do
143
-
144
- it 'should log an exception when the file could not be found' do
145
- expect_log('Attachment upload failed: file does not exist: unknown_file', :error)
146
- expect(@attachments.send(:upload_attachment, nil, 'unknown_file', false)).to be_nil
16
+ def credentials(authentication)
17
+ if authentication == :api_token
18
+ { basic_auth: ['secret', 'x'] }
19
+ else
20
+ { headers: {'Authorization' => 'Bearer secret'} }
147
21
  end
22
+ end
148
23
 
149
- it 'should raise an exception when the file could not be found' do
150
- message = 'Attachment upload failed: file does not exist: unknown_file'
151
- expect{ @attachments.send(:upload_attachment, nil, 'unknown_file', true) }.to raise_error(::Sdk4me::UploadFailed, message)
152
- end
153
-
154
- context 'aws' do
155
- before(:each) do
156
- @aws_conf = {
157
- provider: 'aws',
158
- upload_uri: 'https://itrp.s3.amazonaws.com/',
159
- access_key: 'AKIA6RYQ',
160
- success_url: 'https://mycompany.4me.com/s3_success?sig=99e82e8a046',
161
- policy: 'eydlgIH0=',
162
- signature: 'nbhdec4k=',
163
- upload_path: 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/'
164
- }
165
- @key_template = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}'
166
- @key = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/upload.txt'
167
-
168
- @multi_part_body = "--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"Content-Type\"\r\n\r\napplication/octet-stream\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x-amz-server-side-encryption\"\r\n\r\nAES256\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nattachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\nAKIA6RYQ\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"acl\"\r\n\r\nprivate\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"signature\"\r\n\r\nnbhdec4k=\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"success_action_status\"\r\n\r\n201\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"policy\"\r\n\r\neydlgIH0=\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{@fixture_dir}/upload.txt\"\r\nContent-Type: text/plain\r\n\r\ncontent\r\n--0123456789ABLEWASIEREISAWELBA9876543210--"
169
- @multi_part_headers = {'Accept'=>'*/*', 'Content-Type'=>'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210', 'User-Agent'=>'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6'}
170
- end
171
-
172
- it 'should open a file from disk' do
173
- expect(@attachments).to receive(:aws_upload).with(@aws_conf, @key_template, @key, kind_of(File))
174
- expect(@attachments.send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
175
- end
176
-
177
- it 'should sent the upload to AWS' do
178
- stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: 'OK', status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
179
- stub_request(:get, "https://api.4me.com/v1/s3_success?sig=99e82e8a046&key=#{@key}").with(basic_auth: ['secret', 'x']).to_return(body: {}.to_json)
180
- expect(@attachments.send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
181
- end
24
+ [:api_token, :access_token].each do |authentication|
25
+
26
+ context "#{authentication} - " do
27
+ context 'upload_attachments!' do
28
+ context 'normal' do
29
+ it 'should not do anything when no :attachments are present' do
30
+ expect(attachments(authentication).upload_attachments!('/requests', {status: :in_progress})).to be_nil
31
+ end
32
+
33
+ it 'should not do anything when :attachments is nil' do
34
+ expect(attachments(authentication).upload_attachments!('/requests', {attachments: nil})).to be_nil
35
+ end
36
+
37
+ it 'should not do anything when :attachments is empty' do
38
+ expect(attachments(authentication).upload_attachments!('/requests', {attachments: []})).to be_nil
39
+ expect(attachments(authentication).upload_attachments!('/requests', {attachments: [nil]})).to be_nil
40
+ end
41
+
42
+ it 'should show a error if no attachment may be uploaded' do
43
+ stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {name: 'site 1'}.to_json)
44
+ expect_log('Attachments not allowed for /sites/1', :error)
45
+ expect(attachments(authentication).upload_attachments!('/sites/1', {attachments: ['file1.png']})).to be_nil
46
+ end
47
+
48
+ it 'should raise an exception if no attachment may be uploaded' do
49
+ stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {name: 'site 1'}.to_json)
50
+ message = 'Attachments not allowed for /sites/1'
51
+ expect{ attachments(authentication).upload_attachments!('/sites/1', {attachments: ['file1.png'], attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
52
+ end
53
+
54
+ it 'should add /new to the path for new records' do
55
+ stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {missing: 'storage'}.to_json)
56
+ expect_log('Attachments not allowed for /sites', :error)
57
+ expect(attachments(authentication).upload_attachments!('/sites', {attachments: ['file1.png']})).to be_nil
58
+ end
59
+
60
+ [ [:requests, :note],
61
+ [:problems, :note],
62
+ [:contracts, :remarks],
63
+ [:cis, :remarks],
64
+ [:flsas, :remarks],
65
+ [:slas, :remarks],
66
+ [:service_instances, :remarks],
67
+ [:service_offerings, :summary],
68
+ [:any_other_model, :note]].each do |model, attribute|
69
+
70
+ it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
71
+ stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(credentials(authentication)).to_return(body: {storage_upload: 'conf'}.to_json)
72
+ expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ 'uploaded file1.png' }
73
+ expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ 'uploaded file2.zip' }
74
+ data = {leave: 'me alone', attachments: %w(file1.png file2.zip)}
75
+ attachments(authentication).upload_attachments!("/#{model}", data)
76
+ expect(data[:attachments]).to be_nil
77
+ expect(data[:leave]).to eq('me alone')
78
+ expect(data[:"#{attribute}_attachments"]).to eq(['uploaded file1.png', 'uploaded file2.zip'].to_json)
79
+ end
80
+ end
81
+
82
+ it 'should set raise_exception flag to true when :attachments_exception is set' do
83
+ stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {storage_upload: 'conf'}.to_json)
84
+ expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ 'uploaded file1.png' }
85
+ data = {leave: 'me alone', attachments: 'file1.png', attachments_exception: true}
86
+ attachments(authentication).upload_attachments!('/requests', data)
87
+ expect(data[:attachments]).to be_nil
88
+ expect(data[:attachments_exception]).to be_nil
89
+ expect(data[:leave]).to eq('me alone')
90
+ expect(data[:note_attachments]).to eq(['uploaded file1.png'].to_json)
91
+ end
92
+ end
182
93
 
183
- it 'should report an error when AWS upload fails' do
184
- stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: %(<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>AccessDenied</Code><Message>Invalid according to Policy</Message><RequestId>1FECC4B719E426B1</RequestId><HostId>15+14lXt+HlF</HostId></Error>), status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
185
- expect_log("Attachment upload failed: AWS upload to https://itrp.s3.amazonaws.com/ for #{@key} failed: Invalid according to Policy", :error)
186
- expect(@attachments.send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
187
- end
94
+ context 'inline' do
95
+ it 'should not do anything when no [attachment:...] is present in the note' do
96
+ expect(attachments(authentication).upload_attachments!('/requests', {note: '[attachmen:/type]'})).to be_nil
97
+ end
98
+
99
+ it 'should not do anything when attachment is empty' do
100
+ expect(attachments(authentication).upload_attachments!('/requests', {note: '[attachment:]'})).to be_nil
101
+ end
102
+
103
+ it 'should show a error if no attachment may be uploaded' do
104
+ stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {name: 'site 1'}.to_json)
105
+ expect_log('Attachments not allowed for /sites/1', :error)
106
+ expect(attachments(authentication).upload_attachments!('/sites/1', {note: '[attachment:file1.png]'})).to be_nil
107
+ end
108
+
109
+ it 'should raise an exception if no attachment may be uploaded' do
110
+ stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {name: 'site 1'}.to_json)
111
+ message = 'Attachments not allowed for /sites/1'
112
+ expect{ attachments(authentication).upload_attachments!('/sites/1', {note: '[attachment:file1.png]', attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
113
+ end
114
+
115
+ it 'should add /new to the path for new records' do
116
+ stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {missing: 'storage'}.to_json)
117
+ expect_log('Attachments not allowed for /sites', :error)
118
+ expect(attachments(authentication).upload_attachments!('/sites', {note: '[attachment:file1.png]'})).to be_nil
119
+ end
120
+
121
+ [ [:requests, :note],
122
+ [:problems, :note],
123
+ [:contracts, :remarks],
124
+ [:cis, :remarks],
125
+ [:flsas, :remarks],
126
+ [:slas, :remarks],
127
+ [:service_instances, :remarks],
128
+ [:service_offerings, :summary],
129
+ [:any_other_model, :note]].each do |model, attribute|
130
+
131
+ it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
132
+ stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(credentials(authentication)).to_return(body: {storage_upload: 'conf'}.to_json)
133
+ expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ {key: 'uploaded file1.png'} }
134
+ expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ {key: 'uploaded file2.zip'} }
135
+ data = {leave: 'me alone', attribute => '[attachment:file1.png] and [attachment:file2.zip]'}
136
+ attachments(authentication).upload_attachments!("/#{model}", data)
137
+ expect(data[:attachments]).to be_nil
138
+ expect(data[:leave]).to eq('me alone')
139
+ expect(data[:"#{attribute}_attachments"]).to eq([{key: 'uploaded file1.png', inline: true}, {key: 'uploaded file2.zip', inline: true}].to_json)
140
+ expect(data[:"#{attribute}"]).to eq('![](uploaded file1.png) and ![](uploaded file2.zip)')
141
+ end
142
+ end
143
+
144
+ it 'should set raise_exception flag to true when :attachments_exception is set' do
145
+ stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(credentials(authentication)).to_return(body: {storage_upload: 'conf'}.to_json)
146
+ expect(attachments(authentication)).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ {key: 'uploaded file1.png'} }
147
+ data = {leave: 'me alone', note: '[attachment:file1.png]', attachments_exception: true}
148
+ attachments(authentication).upload_attachments!('/requests', data)
149
+ expect(data[:attachments]).to be_nil
150
+ expect(data[:attachments_exception]).to be_nil
151
+ expect(data[:leave]).to eq('me alone')
152
+ expect(data[:note_attachments]).to eq([{key: 'uploaded file1.png', inline: true}].to_json)
153
+ expect(data[:note]).to eq('![](uploaded file1.png)')
154
+ end
155
+ end
188
156
 
189
- it 'should report an error when 4me confirmation fails' do
190
- stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: 'OK', status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
191
- stub_request(:get, "https://api.4me.com/v1/s3_success?sig=99e82e8a046&key=#{@key}").with(basic_auth: ['secret', 'x']).to_return(body: {message: 'oops!'}.to_json)
192
- expect_log('GET request to api.4me.com:443/v1/s3_success?sig=99e82e8a046&key=attachments%2F5%2Freqs%2F000%2F070%2F451%2Fzxxb4ot60xfd6sjg%2Fupload%2Etxt failed: oops!', :error)
193
- expect_log("Attachment upload failed: 4me confirmation s3_success?sig=99e82e8a046 for #{@key} failed: oops!", :error)
194
- expect(@attachments.send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
195
157
  end
196
158
 
197
- it 'should raise an exception when AWS upload fails' do
198
- stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: %(<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>AccessDenied</Code><Message>Invalid according to Policy</Message><RequestId>1FECC4B719E426B1</RequestId><HostId>15+14lXt+HlF</HostId></Error>), status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
199
- message = "Attachment upload failed: AWS upload to https://itrp.s3.amazonaws.com/ for #{@key} failed: Invalid according to Policy"
200
- expect{ @attachments.send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", true) }.to raise_error(::Sdk4me::UploadFailed, message)
201
- end
202
- end
159
+ context 'upload_attachment' do
203
160
 
204
- context '4me' do
205
- before(:each) do
206
- @sdk4me_conf = {
207
- provider: 'local',
208
- upload_uri: 'https://api.4me.com/attachments',
209
- upload_path: 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/'
210
- }
211
- @key_template = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}'
212
- @key = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/upload.txt'
213
-
214
- @multi_part_body = "--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"Content-Type\"\r\n\r\napplication/octet-stream\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{@spec_dir}/support/fixtures/upload.txt\"\r\nContent-Type: text/plain\r\n\r\ncontent\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nattachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}\r\n--0123456789ABLEWASIEREISAWELBA9876543210--"
215
- @multi_part_headers = {'Accept'=>'*/*', 'Content-Type'=>'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210', 'User-Agent'=>'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6'}
216
- end
161
+ it 'should log an exception when the file could not be found' do
162
+ expect_log('Attachment upload failed: file does not exist: unknown_file', :error)
163
+ expect(attachments(authentication).send(:upload_attachment, nil, 'unknown_file', false)).to be_nil
164
+ end
217
165
 
218
- it 'should open a file from disk' do
219
- expect(@attachments).to receive(:upload_to_4me).with(@sdk4me_conf, @key_template, @key, kind_of(File))
220
- expect(@attachments.send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
221
- end
166
+ it 'should raise an exception when the file could not be found' do
167
+ message = 'Attachment upload failed: file does not exist: unknown_file'
168
+ expect{ attachments(authentication).send(:upload_attachment, nil, 'unknown_file', true) }.to raise_error(::Sdk4me::UploadFailed, message)
169
+ end
222
170
 
223
- it 'should sent the upload to 4me' do
224
- stub_request(:post, 'https://api.4me.com/v1/attachments').with(basic_auth: ['secret', 'x']).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {}.to_json)
225
- expect(@attachments.send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
226
- end
171
+ context 'aws' do
172
+ before(:each) do
173
+ @aws_conf = {
174
+ provider: 'aws',
175
+ upload_uri: 'https://itrp.s3.amazonaws.com/',
176
+ access_key: 'AKIA6RYQ',
177
+ success_url: 'https://mycompany.4me.com/s3_success?sig=99e82e8a046',
178
+ policy: 'eydlgIH0=',
179
+ signature: 'nbhdec4k=',
180
+ upload_path: 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/'
181
+ }
182
+ @key_template = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}'
183
+ @key = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/upload.txt'
184
+
185
+ @multi_part_body = "--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"Content-Type\"\r\n\r\napplication/octet-stream\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x-amz-server-side-encryption\"\r\n\r\nAES256\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nattachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"AWSAccessKeyId\"\r\n\r\nAKIA6RYQ\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"acl\"\r\n\r\nprivate\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"signature\"\r\n\r\nnbhdec4k=\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"success_action_status\"\r\n\r\n201\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"policy\"\r\n\r\neydlgIH0=\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{@fixture_dir}/upload.txt\"\r\nContent-Type: text/plain\r\n\r\ncontent\r\n--0123456789ABLEWASIEREISAWELBA9876543210--"
186
+ @multi_part_headers = {'Accept'=>'*/*', 'Content-Type'=>'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210', 'User-Agent'=>'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6'}
187
+ end
188
+
189
+ it 'should open a file from disk' do
190
+ expect(attachments(authentication)).to receive(:aws_upload).with(@aws_conf, @key_template, @key, kind_of(File))
191
+ expect(attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
192
+ end
193
+
194
+ it 'should sent the upload to AWS' do
195
+ stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: 'OK', status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
196
+ stub_request(:get, "https://api.4me.com/v1/s3_success?sig=99e82e8a046&key=#{@key}").with(credentials(authentication)).to_return(body: {}.to_json)
197
+ expect(attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
198
+ end
199
+
200
+ it 'should report an error when AWS upload fails' do
201
+ stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: %(<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>AccessDenied</Code><Message>Invalid according to Policy</Message><RequestId>1FECC4B719E426B1</RequestId><HostId>15+14lXt+HlF</HostId></Error>), status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
202
+ expect_log("Attachment upload failed: AWS upload to https://itrp.s3.amazonaws.com/ for #{@key} failed: Invalid according to Policy", :error)
203
+ expect(attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
204
+ end
205
+
206
+ it 'should report an error when 4me confirmation fails' do
207
+ stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: 'OK', status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
208
+ stub_request(:get, "https://api.4me.com/v1/s3_success?sig=99e82e8a046&key=#{@key}").with(credentials(authentication)).to_return(body: {message: 'oops!'}.to_json)
209
+ expect_log('GET request to api.4me.com:443/v1/s3_success?sig=99e82e8a046&key=attachments%2F5%2Freqs%2F000%2F070%2F451%2Fzxxb4ot60xfd6sjg%2Fupload%2Etxt failed: oops!', :error)
210
+ expect_log("Attachment upload failed: 4me confirmation s3_success?sig=99e82e8a046 for #{@key} failed: oops!", :error)
211
+ expect(attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
212
+ end
213
+
214
+ it 'should raise an exception when AWS upload fails' do
215
+ stub_request(:post, 'https://itrp.s3.amazonaws.com/').with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: %(<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>AccessDenied</Code><Message>Invalid according to Policy</Message><RequestId>1FECC4B719E426B1</RequestId><HostId>15+14lXt+HlF</HostId></Error>), status: 303, headers: {'Location' => 'https://mycompany.4me.com/s3_success?sig=99e82e8a046'})
216
+ message = "Attachment upload failed: AWS upload to https://itrp.s3.amazonaws.com/ for #{@key} failed: Invalid according to Policy"
217
+ expect{ attachments(authentication).send(:upload_attachment, @aws_conf, "#{@fixture_dir}/upload.txt", true) }.to raise_error(::Sdk4me::UploadFailed, message)
218
+ end
219
+ end
227
220
 
228
- it 'should report an error when 4me upload fails' do
229
- stub_request(:post, 'https://api.4me.com/v1/attachments').with(basic_auth: ['secret', 'x']).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {message: 'oops!'}.to_json)
230
- expect_log('POST request to api.4me.com:443/v1/attachments failed: oops!', :error)
231
- expect_log("Attachment upload failed: 4me upload to https://api.4me.com/attachments for #{@key} failed: oops!", :error)
232
- expect(@attachments.send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
233
- end
221
+ context '4me' do
222
+ before(:each) do
223
+ @sdk4me_conf = {
224
+ provider: 'local',
225
+ upload_uri: 'https://api.4me.com/attachments',
226
+ upload_path: 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/'
227
+ }
228
+ @key_template = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}'
229
+ @key = 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/upload.txt'
230
+
231
+ @multi_part_body = "--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"Content-Type\"\r\n\r\napplication/octet-stream\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{@spec_dir}/support/fixtures/upload.txt\"\r\nContent-Type: text/plain\r\n\r\ncontent\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"key\"\r\n\r\nattachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}\r\n--0123456789ABLEWASIEREISAWELBA9876543210--"
232
+ @multi_part_headers = {'Accept'=>'*/*', 'Content-Type'=>'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210', 'User-Agent'=>'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6'}
233
+ end
234
+
235
+ it 'should open a file from disk' do
236
+ expect(attachments(authentication)).to receive(:upload_to_4me).with(@sdk4me_conf, @key_template, @key, kind_of(File))
237
+ expect(attachments(authentication).send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
238
+ end
239
+
240
+ it 'should sent the upload to 4me' do
241
+ stub_request(:post, 'https://api.4me.com/v1/attachments').with(credentials(authentication)).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {}.to_json)
242
+ expect(attachments(authentication).send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to eq({key: @key, filesize: 7})
243
+ end
244
+
245
+ it 'should report an error when 4me upload fails' do
246
+ stub_request(:post, 'https://api.4me.com/v1/attachments').with(credentials(authentication)).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {message: 'oops!'}.to_json)
247
+ expect_log('POST request to api.4me.com:443/v1/attachments failed: oops!', :error)
248
+ expect_log("Attachment upload failed: 4me upload to https://api.4me.com/attachments for #{@key} failed: oops!", :error)
249
+ expect(attachments(authentication).send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", false)).to be_nil
250
+ end
251
+
252
+ it 'should raise an exception when 4me upload fails' do
253
+ stub_request(:post, 'https://api.4me.com/v1/attachments').with(credentials(authentication)).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {message: 'oops!'}.to_json)
254
+ expect_log('POST request to api.4me.com:443/v1/attachments failed: oops!', :error)
255
+ message = "Attachment upload failed: 4me upload to https://api.4me.com/attachments for #{@key} failed: oops!"
256
+ expect{ attachments(authentication).send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", true) }.to raise_error(::Sdk4me::UploadFailed, message)
257
+ end
258
+ end
234
259
 
235
- it 'should raise an exception when 4me upload fails' do
236
- stub_request(:post, 'https://api.4me.com/v1/attachments').with(basic_auth: ['secret', 'x']).with(body: @multi_part_body, headers: @multi_part_headers).to_return(body: {message: 'oops!'}.to_json)
237
- expect_log('POST request to api.4me.com:443/v1/attachments failed: oops!', :error)
238
- message = "Attachment upload failed: 4me upload to https://api.4me.com/attachments for #{@key} failed: oops!"
239
- expect{ @attachments.send(:upload_attachment, @sdk4me_conf, "#{@fixture_dir}/upload.txt", true) }.to raise_error(::Sdk4me::UploadFailed, message)
240
260
  end
241
261
  end
242
-
243
262
  end
244
263
  end