4me-sdk 2.0.3 → 2.0.6

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