4me-sdk 1.1.8 → 1.2.0

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