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 +4 -4
- data/4me-sdk.gemspec +2 -8
- data/Gemfile +8 -0
- data/README.md +12 -4
- data/lib/sdk4me/client/response.rb +3 -3
- data/lib/sdk4me/client/version.rb +1 -1
- data/lib/sdk4me/client.rb +10 -2
- data/lib/sdk4me.rb +1 -1
- metadata +5 -108
- data/spec/lib/sdk4me/attachments_spec.rb +0 -342
- data/spec/lib/sdk4me/certificate_spec.rb +0 -41
- data/spec/lib/sdk4me/client_spec.rb +0 -598
- data/spec/lib/sdk4me/response_spec.rb +0 -287
- data/spec/lib/sdk4me_spec.rb +0 -33
- data/spec/spec_helper.rb +0 -45
- data/spec/support/fixtures/people.csv +0 -3
- data/spec/support/fixtures/upload.txt +0 -1
- data/spec/support/matchers/never_raise.rb +0 -41
- data/spec/support/util.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 752cf75c3362a0e05579e445ad2856a2695d4f0d4c1c49612fbd46ec790e2ed2
|
4
|
+
data.tar.gz: dbd297eff16730783f20bb43c5dd113e85e7447cf59eb7281727ecf791372c2f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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[:
|
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
|
-
|
303
|
-
|
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)
|
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
|
-
|
107
|
-
|
108
|
-
|
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
|
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
|
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
|
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,
|
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.
|
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:
|
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  Bar ',
|
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  Bar ',
|
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
|