4me-sdk 1.1.7 → 1.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/README.md +8 -0
- data/lib/sdk4me/client.rb +2 -1
- data/lib/sdk4me/client/attachments.rb +52 -9
- data/lib/sdk4me/client/version.rb +1 -1
- data/spec/lib/sdk4me/attachments_spec.rb +117 -51
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aba8de45bcc385f1f8ffedfce680f58cb5c73865510798712d7d8c382ecbd9bf
|
4
|
+
data.tar.gz: 1ffb444710f94ad590aa4943589465e028ad7cf1957bd5546fd93fe158871c6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bdd2c6e55c547a2b13ca893a73e3167d77adee143e53e396b48d8712cfb8d7e148f0f3b10090c3b20691e22b20ddad4a1593d6f8e374880a98c9f8b71abfbe85
|
7
|
+
data.tar.gz: d63bc178ea462a8b4691ad2d63c25ca48ae5735820d398047dfe98ff450be1a6d3f6c8aa8e27c30829afb9753b5213a6f55c0539d1ba03f134908ea8a59ae4f3
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
4me-sdk (1.1.
|
4
|
+
4me-sdk (1.1.8)
|
5
5
|
activesupport (>= 4.2)
|
6
6
|
gem_config (>= 0.3)
|
7
7
|
mime-types (>= 3.0)
|
@@ -16,7 +16,7 @@ GEM
|
|
16
16
|
tzinfo (~> 1.1)
|
17
17
|
addressable (2.5.2)
|
18
18
|
public_suffix (>= 2.0.2, < 4.0)
|
19
|
-
concurrent-ruby (1.1.
|
19
|
+
concurrent-ruby (1.1.5)
|
20
20
|
crack (0.4.3)
|
21
21
|
safe_yaml (~> 1.0.0)
|
22
22
|
diff-lcs (1.3)
|
@@ -28,7 +28,7 @@ GEM
|
|
28
28
|
json (2.1.0)
|
29
29
|
mime-types (3.2.2)
|
30
30
|
mime-types-data (~> 3.2015)
|
31
|
-
mime-types-data (3.
|
31
|
+
mime-types-data (3.2019.0331)
|
32
32
|
minitest (5.11.3)
|
33
33
|
public_suffix (3.0.3)
|
34
34
|
rake (12.3.1)
|
@@ -71,4 +71,4 @@ DEPENDENCIES
|
|
71
71
|
webmock (~> 2)
|
72
72
|
|
73
73
|
BUNDLED WITH
|
74
|
-
1.
|
74
|
+
1.17.3
|
data/README.md
CHANGED
@@ -213,6 +213,14 @@ response = Sdk4me::Client.new.put('requests/416621', {
|
|
213
213
|
})
|
214
214
|
```
|
215
215
|
|
216
|
+
It is also possible to add inline attachments as follows:
|
217
|
+
```
|
218
|
+
response = Sdk4me::Client.new.put('requests/416621', {
|
219
|
+
note: 'Here is some inspiration for you: [attachment:/tmp/images/puppy.png]'
|
220
|
+
})
|
221
|
+
```
|
222
|
+
Note that only images are accepted as inline attachments.
|
223
|
+
|
216
224
|
If an attachment upload fails, the errors are logged but the `post` or `put` request will still be sent to 4me without the
|
217
225
|
failed attachments. To receive exceptions add `attachments_exception: true` to the data.
|
218
226
|
|
data/lib/sdk4me/client.rb
CHANGED
@@ -211,7 +211,8 @@ module Sdk4me
|
|
211
211
|
def expand_header(header = {})
|
212
212
|
header = DEFAULT_HEADER.merge(header)
|
213
213
|
header['X-4me-Account'] = option(:account) if option(:account)
|
214
|
-
|
214
|
+
token_and_password = option(:api_token).include?(':') ? option(:api_token) : "#{option(:api_token)}:x"
|
215
|
+
header['AUTHORIZATION'] = 'Basic ' + [token_and_password].pack('m*').gsub(/\s/, '')
|
215
216
|
if option(:source)
|
216
217
|
header['X-4me-Source'] = option(:source)
|
217
218
|
header['HTTP_USER_AGENT'] = option(:source)
|
@@ -8,21 +8,64 @@ module Sdk4me
|
|
8
8
|
@client = client
|
9
9
|
end
|
10
10
|
|
11
|
-
# upload the attachments
|
11
|
+
# upload the attachments and return the data with the uploaded attachment info
|
12
|
+
# Two flavours available
|
13
|
+
# * data[:attachments]
|
14
|
+
# * data[:note] containing text with '[attachment:/tmp/images/green_fuzz.jpg]'
|
12
15
|
def upload_attachments!(path, data)
|
13
|
-
|
16
|
+
upload_options = {
|
17
|
+
raise_exceptions: !!data.delete(:attachments_exception),
|
18
|
+
attachments_field: attachments_field(path),
|
19
|
+
}
|
20
|
+
uploaded_attachments = upload_normal_attachments!(path, data, upload_options)
|
21
|
+
uploaded_attachments += upload_inline_attachments!(path, data, upload_options)
|
22
|
+
# jsonify the attachments, if any were uploaded
|
23
|
+
data[upload_options[:attachments_field]] = uploaded_attachments.compact.to_json if uploaded_attachments.compact.any?
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# upload the attachments in :attachments to 4me and return the data with the uploaded attachment info
|
29
|
+
def upload_normal_attachments!(path, data, upload_options)
|
14
30
|
attachments = [data.delete(:attachments)].flatten.compact
|
15
|
-
return if attachments.empty?
|
31
|
+
return [] if attachments.empty?
|
16
32
|
|
17
|
-
|
18
|
-
|
19
|
-
report_error("Attachments not allowed for #{path}", raise_exceptions) and return unless storage
|
33
|
+
upload_options[:storage] ||= storage(path, upload_options[:raise_exceptions])
|
34
|
+
return [] unless upload_options[:storage]
|
20
35
|
|
21
|
-
|
22
|
-
|
36
|
+
attachments.map do |attachment|
|
37
|
+
upload_attachment(upload_options[:storage], attachment, upload_options[:raise_exceptions])
|
38
|
+
end
|
23
39
|
end
|
24
40
|
|
25
|
-
|
41
|
+
INLINE_ATTACHMENT_REGEXP = /\[attachment:([^\]]+)\]/.freeze
|
42
|
+
# upload any '[attachment:/tmp/images/green_fuzz.jpg]' in :note text field to 4me as inline attachment and add the s3 key to the text
|
43
|
+
def upload_inline_attachments!(path, data, upload_options)
|
44
|
+
text_field = upload_options[:attachments_field].to_s.gsub('_attachments', '').to_sym
|
45
|
+
return [] unless (data[text_field] || '') =~ INLINE_ATTACHMENT_REGEXP
|
46
|
+
|
47
|
+
upload_options[:storage] ||= storage(path, upload_options[:raise_exceptions])
|
48
|
+
return [] unless upload_options[:storage]
|
49
|
+
|
50
|
+
attachments = []
|
51
|
+
data[text_field] = data[text_field].gsub(INLINE_ATTACHMENT_REGEXP) do |full_match|
|
52
|
+
attachment_details = upload_attachment(upload_options[:storage], $~[1], upload_options[:raise_exceptions])
|
53
|
+
if attachment_details
|
54
|
+
attachments << attachment_details.merge(inline: true)
|
55
|
+
"![](#{attachment_details[:key]})" # magic markdown for inline attachments
|
56
|
+
else
|
57
|
+
full_match
|
58
|
+
end
|
59
|
+
end
|
60
|
+
attachments
|
61
|
+
end
|
62
|
+
|
63
|
+
def storage(path, raise_exceptions)
|
64
|
+
# retrieve the upload configuration for this record from 4me
|
65
|
+
storage = @client.get(path =~ /\d+$/ ? path : "#{path}/new", {attachment_upload_token: true}, @client.send(:expand_header))[:storage_upload]
|
66
|
+
report_error("Attachments not allowed for #{path}", raise_exceptions) unless storage
|
67
|
+
storage
|
68
|
+
end
|
26
69
|
|
27
70
|
def attachments_field(path)
|
28
71
|
case path
|
@@ -8,69 +8,135 @@ describe Sdk4me::Attachments do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
context 'upload_attachments!' do
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
context 'normal' do
|
12
|
+
it 'should not do anything when no :attachments are present' do
|
13
|
+
expect(@attachments.upload_attachments!('/requests', {status: :in_progress})).to be_nil
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
it 'should not do anything when :attachments is nil' do
|
17
|
+
expect(@attachments.upload_attachments!('/requests', {attachments: nil})).to be_nil
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
it 'should not do anything when :attachments is empty' do
|
21
|
+
expect(@attachments.upload_attachments!('/requests', {attachments: []})).to be_nil
|
22
|
+
expect(@attachments.upload_attachments!('/requests', {attachments: [nil]})).to be_nil
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
it 'should show a error if no attachment may be uploaded' do
|
26
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
|
27
|
+
expect_log('Attachments not allowed for /sites/1', :error)
|
28
|
+
expect(@attachments.upload_attachments!('/sites/1', {attachments: ['file1.png']})).to be_nil
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
it 'should raise an exception if no attachment may be uploaded' do
|
32
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
|
33
|
+
message = 'Attachments not allowed for /sites/1'
|
34
|
+
expect{ @attachments.upload_attachments!('/sites/1', {attachments: ['file1.png'], attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
|
35
|
+
end
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
it 'should add /new to the path for new records' do
|
38
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {missing: 'storage'}.to_json)
|
39
|
+
expect_log('Attachments not allowed for /sites', :error)
|
40
|
+
expect(@attachments.upload_attachments!('/sites', {attachments: ['file1.png']})).to be_nil
|
41
|
+
end
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
43
|
+
[ [:requests, :note],
|
44
|
+
[:problems, :note],
|
45
|
+
[:contracts, :remarks],
|
46
|
+
[:cis, :remarks],
|
47
|
+
[:flsas, :remarks],
|
48
|
+
[:slas, :remarks],
|
49
|
+
[:service_instances, :remarks],
|
50
|
+
[:service_offerings, :summary],
|
51
|
+
[:any_other_model, :note]].each do |model, attribute|
|
52
|
+
|
53
|
+
it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
|
54
|
+
stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
|
55
|
+
expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ 'uploaded file1.png' }
|
56
|
+
expect(@attachments).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ 'uploaded file2.zip' }
|
57
|
+
data = {leave: 'me alone', attachments: %w(file1.png file2.zip)}
|
58
|
+
@attachments.upload_attachments!("/#{model}", data)
|
59
|
+
expect(data[:attachments]).to be_nil
|
60
|
+
expect(data[:leave]).to eq('me alone')
|
61
|
+
expect(data[:"#{attribute}_attachments"]).to eq(['uploaded file1.png', 'uploaded file2.zip'].to_json)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should set raise_exception flag to true when :attachments_exception is set' do
|
66
|
+
stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
|
67
|
+
expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ 'uploaded file1.png' }
|
68
|
+
data = {leave: 'me alone', attachments: 'file1.png', attachments_exception: true}
|
69
|
+
@attachments.upload_attachments!('/requests', data)
|
58
70
|
expect(data[:attachments]).to be_nil
|
71
|
+
expect(data[:attachments_exception]).to be_nil
|
59
72
|
expect(data[:leave]).to eq('me alone')
|
60
|
-
expect(data[:
|
73
|
+
expect(data[:note_attachments]).to eq(['uploaded file1.png'].to_json)
|
61
74
|
end
|
62
75
|
end
|
63
76
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
77
|
+
context 'inline' do
|
78
|
+
it 'should not do anything when no [attachment:...] is present in the note' do
|
79
|
+
expect(@attachments.upload_attachments!('/requests', {note: '[attachmen:/type]'})).to be_nil
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should not do anything when attachment is empty' do
|
83
|
+
expect(@attachments.upload_attachments!('/requests', {note: '[attachment:]'})).to be_nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should show a error if no attachment may be uploaded' do
|
87
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
|
88
|
+
expect_log('Attachments not allowed for /sites/1', :error)
|
89
|
+
expect(@attachments.upload_attachments!('/sites/1', {note: '[attachment:file1.png]'})).to be_nil
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should raise an exception if no attachment may be uploaded' do
|
93
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/1?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {name: 'site 1'}.to_json)
|
94
|
+
message = 'Attachments not allowed for /sites/1'
|
95
|
+
expect{ @attachments.upload_attachments!('/sites/1', {note: '[attachment:file1.png]', attachments_exception: true}) }.to raise_error(::Sdk4me::UploadFailed, message)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should add /new to the path for new records' do
|
99
|
+
stub_request(:get, 'https://api.4me.com/v1/sites/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {missing: 'storage'}.to_json)
|
100
|
+
expect_log('Attachments not allowed for /sites', :error)
|
101
|
+
expect(@attachments.upload_attachments!('/sites', {note: '[attachment:file1.png]'})).to be_nil
|
102
|
+
end
|
103
|
+
|
104
|
+
[ [:requests, :note],
|
105
|
+
[:problems, :note],
|
106
|
+
[:contracts, :remarks],
|
107
|
+
[:cis, :remarks],
|
108
|
+
[:flsas, :remarks],
|
109
|
+
[:slas, :remarks],
|
110
|
+
[:service_instances, :remarks],
|
111
|
+
[:service_offerings, :summary],
|
112
|
+
[:any_other_model, :note]].each do |model, attribute|
|
113
|
+
|
114
|
+
it "should replace :attachments with :#{attribute}_attachments after upload at /#{model}" do
|
115
|
+
stub_request(:get, "https://api.4me.com/v1/#{model}/new?attachment_upload_token=true").with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
|
116
|
+
expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', false).ordered{ {key: 'uploaded file1.png'} }
|
117
|
+
expect(@attachments).to receive(:upload_attachment).with('conf', 'file2.zip', false).ordered{ {key: 'uploaded file2.zip'} }
|
118
|
+
data = {leave: 'me alone', attribute => '[attachment:file1.png] and [attachment:file2.zip]'}
|
119
|
+
@attachments.upload_attachments!("/#{model}", data)
|
120
|
+
expect(data[:attachments]).to be_nil
|
121
|
+
expect(data[:leave]).to eq('me alone')
|
122
|
+
expect(data[:"#{attribute}_attachments"]).to eq([{key: 'uploaded file1.png', inline: true}, {key: 'uploaded file2.zip', inline: true}].to_json)
|
123
|
+
expect(data[:"#{attribute}"]).to eq('![](uploaded file1.png) and ![](uploaded file2.zip)')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should set raise_exception flag to true when :attachments_exception is set' do
|
128
|
+
stub_request(:get, 'https://api.4me.com/v1/requests/new?attachment_upload_token=true').with(basic_auth: ['secret', 'x']).to_return(body: {storage_upload: 'conf'}.to_json)
|
129
|
+
expect(@attachments).to receive(:upload_attachment).with('conf', 'file1.png', true).ordered{ {key: 'uploaded file1.png'} }
|
130
|
+
data = {leave: 'me alone', note: '[attachment:file1.png]', attachments_exception: true}
|
131
|
+
@attachments.upload_attachments!('/requests', data)
|
132
|
+
expect(data[:attachments]).to be_nil
|
133
|
+
expect(data[:attachments_exception]).to be_nil
|
134
|
+
expect(data[:leave]).to eq('me alone')
|
135
|
+
expect(data[:note_attachments]).to eq([{key: 'uploaded file1.png', inline: true}].to_json)
|
136
|
+
expect(data[:note]).to eq('![](uploaded file1.png)')
|
137
|
+
end
|
73
138
|
end
|
139
|
+
|
74
140
|
end
|
75
141
|
|
76
142
|
context 'upload_attachment' do
|
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: 1.1.
|
4
|
+
version: 1.1.8
|
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: 2020-02-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gem_config
|