4me-sdk 2.0.3 → 2.0.6

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: da996ddd9ef66ae1e2b296bcf8ae34406163bbcbe157c1dc9ce8809e253468c4
4
- data.tar.gz: 9c4aa5c40c50d5dc9365cb27c89851914d9a3361e6c1df113aa241d00599d522
3
+ metadata.gz: 752cf75c3362a0e05579e445ad2856a2695d4f0d4c1c49612fbd46ec790e2ed2
4
+ data.tar.gz: dbd297eff16730783f20bb43c5dd113e85e7447cf59eb7281727ecf791372c2f
5
5
  SHA512:
6
- metadata.gz: d338d9c4069d1a6d643f04dae0f6e98afe6059f2fa9f5c61f77cdb8869096a468cb369c47d702bec1caf2fff9c7e7d454dd67bc80b89c66dc4ebce8fcaf9b543
7
- data.tar.gz: 7262b78d780457b9569c7143e39e8fbc2e1d13e5fa9d971ce263a1d666327ee7517952c428d20de1e1c851a8f082a7a45508f3abd60cf556950108a1a175d570
6
+ metadata.gz: 5982aab9bfeee3b965e46fcc224a962dce3f24b7944d746bb1d6d231a91ad08d225faf0e96587934a2b54d59f141c1fed0657dc9c9e81323f5e975343db51d26
7
+ data.tar.gz: c052ba87c941f5931571babc0a89409942dcc57adf9cfc753332bae8a7c941eba27f1126b48ad5d9cb401bf56ec0503edd18a46f39e1c5ca770e3eee4343a434
data/4me-sdk.gemspec CHANGED
@@ -3,6 +3,8 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require 'sdk4me/client/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
+ spec.metadata['rubygems_mfa_required'] = 'true'
7
+
6
8
  spec.name = '4me-sdk'
7
9
  spec.version = Sdk4me::Client::VERSION
8
10
  spec.platform = Gem::Platform::RUBY
@@ -22,18 +24,10 @@ Gem::Specification.new do |spec|
22
24
  4me-sdk.gemspec
23
25
  ]
24
26
  spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
25
- spec.test_files = `git ls-files -- {test,spec}/*`.split("\n")
26
27
  spec.require_paths = ['lib']
27
28
  spec.rdoc_options = ['--charset=UTF-8']
28
29
 
29
30
  spec.add_runtime_dependency 'activesupport', '>= 4.2'
30
31
  spec.add_runtime_dependency 'gem_config', '>=0.3'
31
32
  spec.add_runtime_dependency 'mime-types', '>= 3.0'
32
-
33
- spec.add_development_dependency 'bundler'
34
- spec.add_development_dependency 'rake', '~> 12'
35
- spec.add_development_dependency 'rspec', '~> 3.3'
36
- spec.add_development_dependency 'rubocop', '>= 0.49.0'
37
- spec.add_development_dependency 'simplecov', '~> 0'
38
- spec.add_development_dependency 'webmock', '~> 3'
39
33
  end
data/Gemfile CHANGED
@@ -1,4 +1,12 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem 'bundler'
4
+ gem 'json', '>= 2.6'
5
+ gem 'rake', '~> 12'
6
+ gem 'rspec', '~> 3.3'
7
+ gem 'rubocop', '>= 0.49.0'
8
+ gem 'simplecov', '~> 0'
9
+ gem 'webmock', '~> 3'
10
+
3
11
  # Specify your gem's dependencies in 4me-sdk-ruby.gemspec
4
12
  gemspec
data/README.md CHANGED
@@ -263,7 +263,10 @@ begin
263
263
  response = Sdk4me::Client.new.import('\tmp\people.csv', 'people', true)
264
264
  puts response[:state]
265
265
  puts response[:results]
266
- puts response[:message]
266
+ puts response[:logfile]
267
+ unless response.valid?
268
+ puts "Import completed with errors: #{response[:message]}"
269
+ end
267
270
  catch Sdk4me::UploadFailed => ex
268
271
  puts "Could not upload the people import file: #{ex.message}"
269
272
  catch Sdk4me::Exception => ex
@@ -299,8 +302,13 @@ require 'open-uri'
299
302
  begin
300
303
  response = Sdk4me::Client.new.export(['people', 'people_contact_details'], nil, true)
301
304
  puts response[:state]
302
- # write the export file to disk
303
- File.open('/tmp/export.zip', 'wb') { |f| f.write(open(response[:url]).read) }
305
+ if response.valid?
306
+ # write the export file to disk
307
+ File.open('/tmp/export.zip', 'wb') { |f| f.write(open(response[:url]).read) }
308
+ else
309
+ puts "Export failed with errors: #{response[:message]}"
310
+ puts response[:logfile]
311
+ end
304
312
  catch Sdk4me::UploadFailed => ex
305
313
  puts "Could not queue the people export: #{ex.message}"
306
314
  catch Sdk4me::Exception => ex
@@ -353,4 +361,4 @@ The changelog is available [here](CHANGELOG.md).
353
361
 
354
362
  ## Copyright
355
363
 
356
- Copyright (c) 2020 4me, Inc. See [LICENSE](LICENSE) for further details.
364
+ Copyright (c) 2022 4me, Inc. See [LICENSE](LICENSE) for further details.
@@ -103,9 +103,9 @@ module Sdk4me
103
103
  def pagination_link(relation)
104
104
  # split on ',' select the [url] in '<[url]>; rel="[relation]"', compact to all url's found (at most one) and take the first
105
105
  (@pagination_links ||= {})[relation] ||= @response.header['Link'] &&
106
- @response.header['Link']
107
- .split(/,\s*(?:<|$)/)
108
- .map { |link| link[/^\s*<?(.*?)>?;\s*rel="#{relation}"\s*$/, 1] }.compact.first
106
+ @response.header['Link']
107
+ .split(/,\s*(?:<|$)/)
108
+ .map { |link| link[/^\s*<?(.*?)>?;\s*rel="#{relation}"\s*$/, 1] }.compact.first
109
109
  end
110
110
 
111
111
  # pagination urls (relative paths without server) - relations :first, :prev, :next
@@ -1,5 +1,5 @@
1
1
  module Sdk4me
2
2
  class Client
3
- VERSION = '2.0.3'.freeze
3
+ VERSION = '2.0.6'.freeze
4
4
  end
5
5
  end
data/lib/sdk4me/client.rb CHANGED
@@ -72,7 +72,7 @@ module Sdk4me
72
72
  if option(:api_token).blank?
73
73
  raise ::Sdk4me::Exception, 'Missing required configuration option access_token'
74
74
  else
75
- @logger.info('DEPRECATED: Use of api_token is deprecated, switch to using access_token instead. -- https://developer.4me.com/v1/#authentication')
75
+ @logger.info { 'DEPRECATED: Use of api_token is deprecated, switch to using access_token instead. -- https://developer.4me.com/v1/#authentication' }
76
76
  end
77
77
  end
78
78
  @ssl_verify_none = options[:ssl_verify_none]
@@ -88,7 +88,7 @@ module Sdk4me
88
88
  # Returns total nr of resources yielded (for logging)
89
89
  def each(path, params = {}, header = {}, &block)
90
90
  # retrieve the resources using the max page size (least nr of API calls)
91
- next_path = expand_path(path, { per_page: MAX_PAGE_SIZE, page: 1 }.merge(params))
91
+ next_path = expand_path(path, { per_page: MAX_PAGE_SIZE }.merge(params))
92
92
  size = 0
93
93
  while next_path
94
94
  # retrieve the records (with retry and optionally wait for rate-limit)
@@ -145,9 +145,13 @@ module Sdk4me
145
145
  token = response[:token]
146
146
  loop do
147
147
  response = get("/import/#{token}")
148
+ return response if response[:state] == 'error'
149
+
148
150
  unless response.valid?
149
151
  sleep(5)
150
152
  response = get("/import/#{token}") # single retry to recover from a network error
153
+ return response if response[:state] == 'error'
154
+
151
155
  raise ::Sdk4me::Exception, "Unable to monitor progress for #{type} import. #{response.message}" unless response.valid?
152
156
  end
153
157
  # wait 30 seconds while the response is OK and import is still busy
@@ -186,9 +190,13 @@ module Sdk4me
186
190
  token = response[:token]
187
191
  loop do
188
192
  response = get("/export/#{token}")
193
+ return response if response[:state] == 'error'
194
+
189
195
  unless response.valid?
190
196
  sleep(5)
191
197
  response = get("/export/#{token}") # single retry to recover from a network error
198
+ return response if response[:state] == 'error'
199
+
192
200
  raise ::Sdk4me::Exception, "Unable to monitor progress for '#{data[:type]}' export. #{response.message}" unless response.valid?
193
201
  end
194
202
  # wait 30 seconds while the response is OK and export is still busy
data/lib/sdk4me.rb CHANGED
@@ -5,7 +5,7 @@ module Sdk4me
5
5
  include GemConfig::Base
6
6
 
7
7
  with_configuration do
8
- has :logger, classes: ::Logger, default: ::Logger.new($stdout)
8
+ has :logger, default: ::Logger.new($stdout)
9
9
 
10
10
  has :host, classes: String, default: 'https://api.4me.com'
11
11
  has :api_version, values: ['v1'], default: 'v1'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: 4me-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - 4me
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-01 00:00:00.000000000 Z
11
+ date: 2024-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -52,90 +52,6 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rake
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '12'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '12'
83
- - !ruby/object:Gem::Dependency
84
- name: rspec
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: '3.3'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: '3.3'
97
- - !ruby/object:Gem::Dependency
98
- name: rubocop
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: 0.49.0
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: 0.49.0
111
- - !ruby/object:Gem::Dependency
112
- name: simplecov
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: webmock
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '3'
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '3'
139
55
  description: SDK for accessing the 4me REST API
140
56
  email: developers@4me.com
141
57
  executables: []
@@ -154,20 +70,11 @@ files:
154
70
  - lib/sdk4me/client/multipart.rb
155
71
  - lib/sdk4me/client/response.rb
156
72
  - lib/sdk4me/client/version.rb
157
- - spec/lib/sdk4me/attachments_spec.rb
158
- - spec/lib/sdk4me/certificate_spec.rb
159
- - spec/lib/sdk4me/client_spec.rb
160
- - spec/lib/sdk4me/response_spec.rb
161
- - spec/lib/sdk4me_spec.rb
162
- - spec/spec_helper.rb
163
- - spec/support/fixtures/people.csv
164
- - spec/support/fixtures/upload.txt
165
- - spec/support/matchers/never_raise.rb
166
- - spec/support/util.rb
167
73
  homepage: https://github.com/code4me/4me-sdk-ruby
168
74
  licenses:
169
75
  - MIT
170
- metadata: {}
76
+ metadata:
77
+ rubygems_mfa_required: 'true'
171
78
  post_install_message:
172
79
  rdoc_options:
173
80
  - "--charset=UTF-8"
@@ -189,14 +96,4 @@ signing_key:
189
96
  specification_version: 4
190
97
  summary: The official 4me SDK for Ruby. Provides easy access to the REST APIs found
191
98
  at https://developer.4me.com
192
- test_files:
193
- - spec/lib/sdk4me/attachments_spec.rb
194
- - spec/lib/sdk4me/certificate_spec.rb
195
- - spec/lib/sdk4me/client_spec.rb
196
- - spec/lib/sdk4me/response_spec.rb
197
- - spec/lib/sdk4me_spec.rb
198
- - spec/spec_helper.rb
199
- - spec/support/fixtures/people.csv
200
- - spec/support/fixtures/upload.txt
201
- - spec/support/matchers/never_raise.rb
202
- - spec/support/util.rb
99
+ test_files: []
@@ -1,342 +0,0 @@
1
- require 'spec_helper'
2
- require 'tempfile'
3
-
4
- describe Sdk4me::Attachments do
5
- def attachments(authentication, path)
6
- @client = if authentication == :api_token
7
- Sdk4me::Client.new(api_token: 'secret', max_retry_time: -1)
8
- else
9
- Sdk4me::Client.new(access_token: 'secret', max_retry_time: -1)
10
- end
11
- Sdk4me::Attachments.new(@client, path)
12
- end
13
-
14
- def credentials(authentication)
15
- if authentication == :api_token
16
- { basic_auth: %w[secret x] }
17
- else
18
- { headers: { 'Authorization' => 'Bearer secret' } }
19
- end
20
- end
21
-
22
- %i[api_token access_token].each do |authentication|
23
- context "#{authentication} -" do
24
- context 'upload_attachments! -' do
25
- context 'field attachments' do
26
- it 'should not do anything when no attachments are present' do
27
- a = attachments(authentication, '/requests')
28
- expect(@client).not_to receive(:send_file)
29
- a.upload_attachments!({ status: :in_progress })
30
- end
31
-
32
- it 'should not do anything when attachments is nil' do
33
- a = attachments(authentication, '/requests')
34
- expect(@client).not_to receive(:send_file)
35
- a.upload_attachments!({ note_attachments: nil })
36
- end
37
-
38
- it 'should not do anything when attachments is empty' do
39
- a = attachments(authentication, '/requests')
40
- expect(@client).not_to receive(:send_file)
41
- a.upload_attachments!({ note_attachments: [] })
42
- a.upload_attachments!({ note_attachments: [nil] })
43
- end
44
-
45
- it 'should raise an error if no attachment provider can be determined' do
46
- a = attachments(authentication, '/requests')
47
- expect(@client).not_to receive(:send_file)
48
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 404, body: { message: 'Not Found' }.to_json)
49
- expect_log('GET request to api.4me.com:443/v1/attachments/storage failed: 404: Not Found', :error)
50
- expect_log('Attachment upload failed: No provider found', :error)
51
- expect { a.upload_attachments!({ note_attachments: ['file1.png'] }) }.to raise_error(::Sdk4me::UploadFailed, 'Attachment upload failed: No provider found')
52
- end
53
-
54
- it 'should upload' do
55
- a = attachments(authentication, '/requests')
56
- resp = {
57
- provider: 'local',
58
- upload_uri: 'https://widget.example.com/attachments',
59
- local: {
60
- key: 'attachments/5/requests/000/000/777/abc/${filename}',
61
- x_4me_expiration: '2020-11-01T23:59:59Z',
62
- x_4me_signature: 'foobar'
63
- }
64
- }
65
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 200, body: resp.to_json)
66
-
67
- expect(a).to(receive(:upload_attachment).with('/tmp/file1.png').ordered { { key: 'attachments/5/requests/000/000/777/abc/file1.png', filesize: 1234 } })
68
- expect(a).to(receive(:upload_attachment).with('/tmp/file2.zip').ordered { { key: 'attachments/5/requests/000/000/777/abc/file2.zip', filesize: 9876 } })
69
-
70
- data = { subject: 'Foobar', note_attachments: ['/tmp/file1.png', '/tmp/file2.zip'] }
71
- a.upload_attachments!(data)
72
- expect(data).to eq({ subject: 'Foobar', note_attachments: [
73
- { filesize: 1234, key: 'attachments/5/requests/000/000/777/abc/file1.png' },
74
- { filesize: 9876, key: 'attachments/5/requests/000/000/777/abc/file2.zip' }
75
- ] })
76
- end
77
- end
78
-
79
- context 'rich text inline attachments' do
80
- it 'should not do anything when no [note_attachments: <idx>] is present in the note' do
81
- a = attachments(authentication, '/requests')
82
- expect(@client).not_to receive(:send_file)
83
- data = { note: '[note_attachments: foo]' }
84
- a.upload_attachments!(data)
85
- expect(data).to eq({ note: '[note_attachments: foo]' })
86
- end
87
-
88
- it 'should not do anything when note attachments is empty' do
89
- a = attachments(authentication, '/requests')
90
- expect(@client).not_to receive(:send_file)
91
- data = { note: '[note_attachments: 0]' }
92
- a.upload_attachments!(data)
93
- expect(data).to eq({ note: '[note_attachments: 0]' })
94
- end
95
-
96
- it 'should raise an error if no attachment provider can be determined' do
97
- a = attachments(authentication, '/requests')
98
- expect(@client).not_to receive(:send_file)
99
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 404, body: { message: 'Not Found' }.to_json)
100
- expect_log('GET request to api.4me.com:443/v1/attachments/storage failed: 404: Not Found', :error)
101
- expect_log('Attachment upload failed: No provider found', :error)
102
- data = {
103
- note: '[note_attachments: 0]', note_attachments: ['/tmp/doesnotexist.log']
104
- }
105
- expect { a.upload_attachments!(data) }.to raise_error(::Sdk4me::UploadFailed, 'Attachment upload failed: No provider found')
106
- end
107
-
108
- it 'should upload' do
109
- a = attachments(authentication, '/requests')
110
- resp = {
111
- provider: 'local',
112
- upload_uri: 'https://widget.example.com/attachments',
113
- local: {
114
- key: 'attachments/5/requests/000/000/777/abc/${filename}',
115
- x_4me_expiration: '2020-11-01T23:59:59Z',
116
- x_4me_signature: 'foobar'
117
- }
118
- }
119
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 200, body: resp.to_json)
120
-
121
- expect(a).to(receive(:upload_attachment).with('/tmp/file1.png').ordered { { key: 'attachments/5/requests/000/000/777/abc/file1.png', filesize: 1234 } })
122
- expect(a).to(receive(:upload_attachment).with('/tmp/file2.jpg').ordered { { key: 'attachments/5/requests/000/000/777/abc/file2.jpg', filesize: 9876 } })
123
-
124
- data = {
125
- subject: 'Foobar',
126
- note: 'Foo [note_attachments: 0] Bar [note_attachments: 1]',
127
- note_attachments: ['/tmp/file1.png', '/tmp/file2.jpg']
128
- }
129
- a.upload_attachments!(data)
130
-
131
- expect(data).to eq({
132
- note: 'Foo ![](attachments/5/requests/000/000/777/abc/file1.png) Bar ![](attachments/5/requests/000/000/777/abc/file2.jpg)',
133
- note_attachments: [
134
- { filesize: 1234, inline: true, key: 'attachments/5/requests/000/000/777/abc/file1.png' },
135
- { filesize: 9876, inline: true, key: 'attachments/5/requests/000/000/777/abc/file2.jpg' }
136
- ],
137
- subject: 'Foobar'
138
- })
139
- end
140
- end
141
-
142
- context 'field attachments and rich text inline attachments' do
143
- it 'should upload, and replace the data in place' do
144
- a = attachments(authentication, '/requests')
145
- resp = {
146
- provider: 'local',
147
- upload_uri: 'https://widget.example.com/attachments',
148
- local: {
149
- key: 'attachments/5/requests/000/000/777/abc/${filename}',
150
- x_4me_expiration: '2020-11-01T23:59:59Z',
151
- x_4me_signature: 'foobar'
152
- }
153
- }
154
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 200, body: resp.to_json)
155
-
156
- expect(a).to(receive(:upload_attachment).with('/tmp/file3.log').ordered { { key: 'attachments/5/requests/000/000/777/abc/file3.log', filesize: 5678 } })
157
- expect(a).to(receive(:upload_attachment).with('/tmp/file1.png').ordered { { key: 'attachments/5/requests/000/000/777/abc/file1.png', filesize: 1234 } })
158
- expect(a).to(receive(:upload_attachment).with('/tmp/file2.jpg').ordered { { key: 'attachments/5/requests/000/000/777/abc/file2.jpg', filesize: 9876 } })
159
-
160
- data = {
161
- subject: 'Foobar',
162
- note: 'Foo [note_attachments: 2] Bar [note_attachments: 1]',
163
- note_attachments: ['/tmp/file3.log', '/tmp/file1.png', '/tmp/file2.jpg']
164
- }
165
- a.upload_attachments!(data)
166
-
167
- expect(data).to eq({
168
- note: 'Foo ![](attachments/5/requests/000/000/777/abc/file2.jpg) Bar ![](attachments/5/requests/000/000/777/abc/file1.png)',
169
- note_attachments: [
170
- { filesize: 5678, key: 'attachments/5/requests/000/000/777/abc/file3.log' },
171
- { filesize: 1234, inline: true, key: 'attachments/5/requests/000/000/777/abc/file1.png' },
172
- { filesize: 9876, inline: true, key: 'attachments/5/requests/000/000/777/abc/file2.jpg' }
173
- ],
174
- subject: 'Foobar'
175
- })
176
- end
177
-
178
- it 'failed uploads' do
179
- a = attachments(authentication, '/requests')
180
- resp = {
181
- provider: 'local',
182
- upload_uri: 'https://widget.example.com/attachments',
183
- local: {
184
- key: 'attachments/5/requests/000/000/777/abc/${filename}',
185
- x_4me_expiration: '2020-11-01T23:59:59Z',
186
- x_4me_signature: 'foobar'
187
- }
188
- }
189
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 200, body: resp.to_json)
190
-
191
- expect_log('Attachment upload failed: file does not exist: /tmp/doesnotexist.png', :error)
192
-
193
- data = {
194
- subject: 'Foobar',
195
- note: 'Foo [note_attachments: 2] Bar [note_attachments: 1]',
196
- note_attachments: ['/tmp/doesnotexist.png']
197
- }
198
- expect { a.upload_attachments!(data) }.to raise_error(::Sdk4me::UploadFailed, 'Attachment upload failed: file does not exist: /tmp/doesnotexist.png')
199
- end
200
- end
201
- end
202
-
203
- context :upload_attachment do
204
- before(:each) do
205
- resp = {
206
- provider: 'local',
207
- upload_uri: 'https://widget.example.com/attachments',
208
- local: {
209
- key: 'attachments/5/requests/000/000/777/abc/${filename}',
210
- x_4me_expiration: '2020-11-01T23:59:59Z',
211
- x_4me_signature: 'foobar'
212
- }
213
- }
214
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 200, body: resp.to_json)
215
- end
216
-
217
- it 'should raise an error when the file could not be found' do
218
- a = attachments(authentication, '/requests')
219
- expect(@client).not_to receive(:send_file)
220
- message = 'Attachment upload failed: file does not exist: /tmp/unknown_file'
221
- expect_log(message, :error)
222
- expect { a.send(:upload_attachment, '/tmp/unknown_file') }.to raise_error(::Sdk4me::UploadFailed, message)
223
- end
224
- end
225
-
226
- context :s3 do
227
- before(:each) do
228
- resp = {
229
- provider: 's3',
230
- upload_uri: 'https://example.s3-accelerate.amazonaws.com/',
231
- s3: {
232
- acl: 'private',
233
- key: 'attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/${filename}',
234
- policy: 'eydlgIH0=',
235
- success_action_status: 201,
236
- x_amz_algorithm: 'AWS4-HMAC-SHA256',
237
- x_amz_credential: 'AKIATRO999Z9E9D2EQ7B/20201107/us-east-1/s3/aws4_request',
238
- x_amz_date: '20201107T000000Z',
239
- x_amz_server_side_encryption: 'AES256',
240
- x_amz_signature: 'nbhdec4k='
241
- }
242
- }
243
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 200, body: resp.to_json)
244
- end
245
-
246
- it 'should upload a file from disk' do
247
- Tempfile.create('4me_attachments_spec.txt') do |file|
248
- file << 'foobar'
249
- file.flush
250
-
251
- a = attachments(authentication, '/requests')
252
-
253
- stub_request(:post, 'https://example.s3-accelerate.amazonaws.com/')
254
- .with(
255
- 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=\"acl\"\r\n\r\nprivate\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=\"policy\"\r\n\r\neydlgIH0=\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=\"x_amz_algorithm\"\r\n\r\nAWS4-HMAC-SHA256\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x_amz_credential\"\r\n\r\nAKIATRO999Z9E9D2EQ7B/20201107/us-east-1/s3/aws4_request\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x_amz_date\"\r\n\r\n20201107T000000Z\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=\"x_amz_signature\"\r\n\r\nnbhdec4k=\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{file.path}\"\r\nContent-Type: application/octet-stream\r\n\r\nfoobar\r\n--0123456789ABLEWASIEREISAWELBA9876543210--",
256
- headers: {
257
- 'Accept' => '*/*',
258
- 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
259
- 'Content-Type' => 'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210',
260
- '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 4me/#{Sdk4me::Client::VERSION}"
261
- }
262
- )
263
- .to_return(status: 200, headers: {}, body: %(<?xml version="1.0" encoding="UTF-8"?>\n<PostResponse><Location>foo</Location><Bucket>example</Bucket><Key>attachments/5/zxxb4ot60xfd6sjg/s3test.txt</Key><ETag>"bar"</ETag></PostResponse>))
264
-
265
- expect(a.send(:upload_attachment, file.path)).to eq({
266
- key: 'attachments/5/zxxb4ot60xfd6sjg/s3test.txt',
267
- filesize: 6
268
- })
269
- end
270
- end
271
-
272
- it 'should report an error when upload fails' do
273
- Tempfile.create('4me_attachments_spec.txt') do |file|
274
- file << 'foobar'
275
- file.flush
276
-
277
- a = attachments(authentication, '/requests')
278
-
279
- stub_request(:post, 'https://example.s3-accelerate.amazonaws.com/')
280
- .with(
281
- 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=\"acl\"\r\n\r\nprivate\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=\"policy\"\r\n\r\neydlgIH0=\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=\"x_amz_algorithm\"\r\n\r\nAWS4-HMAC-SHA256\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x_amz_credential\"\r\n\r\nAKIATRO999Z9E9D2EQ7B/20201107/us-east-1/s3/aws4_request\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x_amz_date\"\r\n\r\n20201107T000000Z\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=\"x_amz_signature\"\r\n\r\nnbhdec4k=\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{file.path}\"\r\nContent-Type: application/octet-stream\r\n\r\nfoobar\r\n--0123456789ABLEWASIEREISAWELBA9876543210--",
282
- headers: {
283
- 'Accept' => '*/*',
284
- 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
285
- 'Content-Type' => 'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210',
286
- '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 4me/#{Sdk4me::Client::VERSION}"
287
- }
288
- )
289
- .to_return(status: 400, body: '<Error><Message>Foo Bar Failure</Message></Error>', headers: {})
290
-
291
- key = "attachments/5/reqs/000/070/451/zxxb4ot60xfd6sjg/#{File.basename(file.path)}"
292
- message = "Attachment upload failed: AWS S3 upload to https://example.s3-accelerate.amazonaws.com/ for #{key} failed: Foo Bar Failure"
293
- # expect_log(message, :error)
294
- expect { a.send(:upload_attachment, file.path) }.to raise_error(::Sdk4me::UploadFailed, message)
295
- end
296
- end
297
- end
298
-
299
- context '4me local' do
300
- before(:each) do
301
- resp = {
302
- provider: 'local',
303
- upload_uri: 'https://widget.example.com/attachments',
304
- local: {
305
- key: 'attachments/5/requests/000/000/777/abc/${filename}',
306
- x_4me_expiration: '2020-11-01T23:59:59Z',
307
- x_4me_signature: 'foobar'
308
- }
309
- }
310
- stub_request(:get, 'https://api.4me.com/v1/attachments/storage').with(credentials(authentication)).to_return(status: 200, body: resp.to_json)
311
- end
312
-
313
- it 'should upload a file from disk' do
314
- Tempfile.create('4me_我attáchments_spec.txt') do |file|
315
- file << 'foobar'
316
- file.flush
317
-
318
- a = attachments(authentication, '/requests')
319
-
320
- stub_request(:post, 'https://widget.example.com/attachments')
321
- .with(
322
- 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=\"key\"\r\n\r\nattachments/5/requests/000/000/777/abc/${filename}\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x_4me_expiration\"\r\n\r\n2020-11-01T23:59:59Z\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"x_4me_signature\"\r\n\r\nfoobar\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{file.path}\"\r\nContent-Type: application/octet-stream\r\n\r\nfoobar\r\n--0123456789ABLEWASIEREISAWELBA9876543210--",
323
- headers: {
324
- 'Accept' => '*/*',
325
- 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
326
- 'Authorization' => (authentication == :api_token ? 'Basic c2VjcmV0Ong=' : 'Bearer secret'),
327
- 'Content-Type' => 'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210',
328
- '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 4me/#{Sdk4me::Client::VERSION}"
329
- }
330
- )
331
- .to_return(status: 200, headers: {}, body: %({"key":"attachments/5/zxxb4ot60xfd6sjg/s3test.txt"}))
332
-
333
- expect(a.send(:upload_attachment, file.path)).to eq({
334
- key: 'attachments/5/zxxb4ot60xfd6sjg/s3test.txt',
335
- filesize: 6
336
- })
337
- end
338
- end
339
- end
340
- end
341
- end
342
- end