4me-sdk 1.1.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 885049091080590a682f5fa2df6320a55d251ab5
4
+ data.tar.gz: 8f119ed9d892fa6abb55ac2aafafd297a8f2e617
5
+ SHA512:
6
+ metadata.gz: 72ce9082f51ad8f90626f7039a9ce2c67616dd6983616592d92572b9801880b92a033ac18cae8616c254fbdb917e388bfa436a7694324a18b9794a3ce9ac9806
7
+ data.tar.gz: e998fc6b6f19f313039a793cfb7357c9aabf8e05c8a65e67a718c449bed7a5e053a563204dd57f0e946f11d042d08977fde8f2be36f52ca95d2f419f3b3a1103
data/4me-sdk.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sdk4me/client/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = '4me-sdk'
8
+ spec.version = Sdk4me::Client::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.required_ruby_version = '>= 2.0.0'
11
+ spec.authors = ['4me']
12
+ spec.email = %q{developers@4me.com}
13
+ spec.description = %q{SDK for accessing the 4me}
14
+ spec.summary = %q{The official 4me SDK for Ruby. Provides easy access to the APIs found at https://developer.4me.com}
15
+ spec.homepage = %q{https://github.com/code4me/4me-sdk-ruby}
16
+ spec.license = 'MIT'
17
+
18
+ spec.files = Dir.glob('lib/**/*') + %w(
19
+ LICENSE
20
+ README.md
21
+ Gemfile
22
+ Gemfile.lock
23
+ 4me-sdk.gemspec
24
+ )
25
+ spec.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ spec.test_files = `git ls-files -- {test,spec}/*`.split("\n")
27
+ spec.require_paths = ['lib']
28
+ spec.rdoc_options = ['--charset=UTF-8']
29
+
30
+ spec.add_runtime_dependency 'gem_config', '>=0.3'
31
+ spec.add_runtime_dependency 'activesupport', '>= 4.2'
32
+ spec.add_runtime_dependency 'mime-types', '>= 3.0'
33
+
34
+ spec.add_development_dependency 'bundler', '~> 1'
35
+ spec.add_development_dependency 'rake', '~> 12'
36
+ spec.add_development_dependency 'rspec', '~> 3.3'
37
+ spec.add_development_dependency 'webmock', '~> 2'
38
+ spec.add_development_dependency 'simplecov', '~> 0'
39
+
40
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in 4me-sdk-ruby.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,74 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ 4me-sdk (1.1.2)
5
+ activesupport
6
+ gem_config
7
+ mime-types
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activesupport (5.2.1)
13
+ concurrent-ruby (~> 1.0, >= 1.0.2)
14
+ i18n (>= 0.7, < 2)
15
+ minitest (~> 5.1)
16
+ tzinfo (~> 1.1)
17
+ addressable (2.5.2)
18
+ public_suffix (>= 2.0.2, < 4.0)
19
+ concurrent-ruby (1.1.3)
20
+ crack (0.4.3)
21
+ safe_yaml (~> 1.0.0)
22
+ diff-lcs (1.3)
23
+ docile (1.3.1)
24
+ gem_config (0.3.1)
25
+ hashdiff (0.3.7)
26
+ i18n (1.1.1)
27
+ concurrent-ruby (~> 1.0)
28
+ json (2.1.0)
29
+ mime-types (3.2.2)
30
+ mime-types-data (~> 3.2015)
31
+ mime-types-data (3.2018.0812)
32
+ minitest (5.11.3)
33
+ public_suffix (3.0.3)
34
+ rake (12.3.1)
35
+ rspec (3.3.0)
36
+ rspec-core (~> 3.3.0)
37
+ rspec-expectations (~> 3.3.0)
38
+ rspec-mocks (~> 3.3.0)
39
+ rspec-core (3.3.2)
40
+ rspec-support (~> 3.3.0)
41
+ rspec-expectations (3.3.1)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.3.0)
44
+ rspec-mocks (3.3.2)
45
+ diff-lcs (>= 1.2.0, < 2.0)
46
+ rspec-support (~> 3.3.0)
47
+ rspec-support (3.3.0)
48
+ safe_yaml (1.0.4)
49
+ simplecov (0.16.1)
50
+ docile (~> 1.1)
51
+ json (>= 1.8, < 3)
52
+ simplecov-html (~> 0.10.0)
53
+ simplecov-html (0.10.2)
54
+ thread_safe (0.3.6)
55
+ tzinfo (1.2.5)
56
+ thread_safe (~> 0.1)
57
+ webmock (2.3.2)
58
+ addressable (>= 2.3.6)
59
+ crack (>= 0.3.2)
60
+ hashdiff
61
+
62
+ PLATFORMS
63
+ ruby
64
+
65
+ DEPENDENCIES
66
+ 4me-sdk!
67
+ bundler (~> 1)
68
+ rake (~> 12)
69
+ rspec (~> 3.3)
70
+ simplecov (~> 0)
71
+ webmock (~> 2)
72
+
73
+ BUNDLED WITH
74
+ 1.16.1
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 https://code.4me.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,324 @@
1
+ # Sdk4me::Client
2
+
3
+ Client for accessing the [4me REST API](http://developer.4me.com/v1/)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem '4me-sdk'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install 4me-sdk
18
+
19
+ ## Configuration
20
+
21
+ ### Global
22
+
23
+ ```
24
+ Sdk4me.configure do |config|
25
+ config.api_token = 'd41f5868feb65fc87fa2311a473a8766ea38bc40'
26
+ config.account = 'my-sandbox'
27
+ config.logger = Rails.logger
28
+ ...
29
+ end
30
+ ```
31
+
32
+ All options available:
33
+
34
+ * _logger_: The [Ruby Logger](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html) instance, default: `Logger.new(STDOUT)`
35
+ * _host_: The [4me API host](http://developer.4me.com/v1/#service-url), default: 'https://api.4me.com'
36
+ * _api_version_: The [4me API version](http://developer.4me.com/v1/#service-url), default: 'v1'
37
+ * _api_token_: (**required**) The [4me API token](http://developer.4me.com/v1/#api-tokens)
38
+ * _account_: Specify a [different account](http://developer.4me.com/v1/#multiple-accounts) to work with
39
+ * _source_: The [source](http://developer.4me.com/v1/general/source/) used when creating new records
40
+ * _max_retry_time_: maximum nr of seconds to wait for server to respond (default = 5400 = 1.5 hours)<br/>
41
+ The sleep time between retries starts at 2 seconds and doubles after each retry, i.e.
42
+ 2, 6, 18, 54, 162, 486, 1458, 4374, 13122, ... seconds.<br/>
43
+ One retry will always be performed unless you set the value to -1.
44
+ * _read_timeout_: [HTTP read timeout](http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-read_timeout-3D) in seconds (default = 25)
45
+ * _block_at_rate_limit_: Set to `true` to block the request until the [rate limit](http://developer.4me.com/v1/#rate-limiting) is lifted, default: `false`
46
+ * _proxy_host_: Define in case HTTP traffic needs to go through a proxy
47
+ * _proxy_port_: Port of the proxy, defaults to 8080
48
+ * _proxy_user_: Proxy user
49
+ * _proxy_password_: Proxy password
50
+ * _ca_file_: Certificate file (defaults to the provided ca-bundle.crt file from Mozilla)
51
+
52
+ ### Override
53
+
54
+ Each time an 4me SDK Client is instantiated it is possible to override the [global configuration](#global-configuration) like so:
55
+
56
+ ```
57
+ client = Sdk4me::Client.new(account: 'trusted-sandbox', source: 'my special integration')
58
+ ```
59
+
60
+ ### Proxy
61
+
62
+ The proxy settings are limited to basic authentication only. In case ISA-NTLM authentication is required, make sure to setup a local proxy configured to forward the requests. And example local proxy host for Windows is [Fiddle](http://www.telerik.com/fiddler).
63
+
64
+ ## 4me SDK Client
65
+
66
+ Minimal example:
67
+
68
+ ```
69
+ require 'sdk4me/client'
70
+
71
+ client = Sdk4me::Client.new(api_token: '3a4e4590179263839...')
72
+ response = client.get('me')
73
+ puts response[:primary_email]
74
+ ```
75
+
76
+ ### Retrieve a single record
77
+
78
+ The `get` method can be used to retrieve a single record from SDK4ME.
79
+
80
+ ```
81
+ response = Sdk4me::Client.new.get('organizations/4321')
82
+ puts response[:name]
83
+ ```
84
+
85
+ By default this call will return all [fields](http://developer.4me.com/v1/organizations/#fields) of the Organization.
86
+
87
+ The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
88
+ ```
89
+ response = Sdk4me::Client.new.get('organizations/4321')
90
+ puts response[:parent][:name] # this may throw an error when +parent+ is +nil+
91
+ puts response[:parent, :name] # using this format you will retrieve +nil+ when +parent+ is +nil+
92
+ puts response['parent', 'name'] # strings are also accepted as keys
93
+ ```
94
+
95
+ ### Browse through a collection of records
96
+
97
+ Although the `get` method can be also used to retrieve a collection of records from SDK4ME, the preferred way is to use the `each` method.
98
+
99
+ ```
100
+ count = Sdk4me::Client.new.each('organizations') do |organization|
101
+ puts organization[:name]
102
+ end
103
+ puts "Found #{count} organizations"
104
+ ```
105
+
106
+ By default this call will return all [collection fields](http://developer.4me.com/v1/organizations/#collection-fields) for each Organization.
107
+ For more fields, check out the [field selection](http://developer.4me.com/v1/general/field_selection/#collection-of-resources) documentation.
108
+
109
+ The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
110
+ ```
111
+ count = Sdk4me::Client.new.each('organizations', fields: 'parent') do |organization|
112
+ puts organization[:parent][:name] # this may throw an error when +parent+ is +nil+
113
+ puts organization[:parent, :name] # using this format you will retrieve +nil+ when +parent+ is +nil+
114
+ puts organization['parent', 'name'] # strings are also accepted as keys
115
+ end
116
+ ```
117
+
118
+ Note that an `Sdk4me::Exception` could be thrown in case one of the API requests fails. When using the [blocking options](#blocking) the chances of this happening are rather small and you may decide not to explicitly catch the `Sdk4me::Exception` here, but leave it up to a generic exception handler.
119
+
120
+ ### Retrieve a collection of records
121
+
122
+ The `each` method [described above](#browse-through-a-collection-of-records) is the preferred way to work with collections of data.
123
+
124
+ If you really want to [paginate](http://developer.4me.com/v1/general/pagination/) yourself, the `get` method is your friend.
125
+
126
+ ```
127
+ @client = Sdk4me::Client.new
128
+ response = @client.get('organizations', {per_page: 10, page: 2})
129
+
130
+ puts response.json # all data in an array
131
+
132
+ puts "showing page #{response.current_page}/#{response.total_pages}, with #{response.per_page} records per page"
133
+ puts "total number of records #{response.total_entries}"
134
+
135
+ # retrieve collection for other pages directly from the response
136
+ first_page = @client.get(response.pagination_link(:first))
137
+ prev_page = @client.get(response.pagination_link(:prev))
138
+ next_page = @client.get(response.pagination_link(:next))
139
+ last_page = @client.get(response.pagination_link(:last))
140
+ ```
141
+
142
+ By default this call will return all [collection fields](http://developer.4me.com/v1/organizations/#collection-fields) for each Organization.
143
+ For more fields, check out the [field selection](http://developer.4me.com/v1/general/field_selection/#collection-of-resources) documentation.
144
+
145
+ The fields can be accessed using *symbols* and *strings*, and it is possible chain a number of keys in one go:
146
+ ```
147
+ response = Sdk4me::Client.new.get('organizations', {per_page: 10, page: 2, fields: 'parent'})
148
+ puts response[:parent, :name] # an array with the parent organization names
149
+ puts response['parent', 'name'] # strings are also accepted as keys
150
+ ```
151
+
152
+ ### Create a new record
153
+
154
+ Creating new records is done using the `post` method.
155
+
156
+ ```
157
+ response = Sdk4me::Client.new.post('people', {primary_email: 'new.user@example.com', organization_id: 777})
158
+ if response.valid?
159
+ puts "New person created with id #{response[:id]}"
160
+ else
161
+ puts response.message
162
+ end
163
+ ```
164
+
165
+ Make sure to validate the success by calling `response.valid?` and to take appropriate action in case the response is not valid.
166
+
167
+
168
+ ### Update an existing record
169
+
170
+ Updating records is done using the `put` method.
171
+
172
+ ```
173
+ response = Sdk4me::Client.new.put('people/888', {name: 'Mrs. Susan Smith', organization_id: 777})
174
+ if response.valid?
175
+ puts "Person with id #{response[:id]} successfully updated"
176
+ else
177
+ puts response.message
178
+ end
179
+ ```
180
+
181
+ Make sure to validate the success by calling `response.valid?` and to take appropriate action in case the response is not valid.
182
+
183
+ ### Delete an existing record
184
+
185
+ Deleting records is done using the `delete` method.
186
+
187
+ ```
188
+ response = Sdk4me::Client.new.delete('organizations/88/addresses/')
189
+ if response.valid?
190
+ puts "Addresses of Organization with id #{response[:id]} successfully removed"
191
+ else
192
+ puts response.message
193
+ end
194
+ ```
195
+
196
+ Make sure to validate the success by calling `response.valid?` and to take appropriate action in case the response is not valid.
197
+
198
+
199
+ ### Note Attachments
200
+
201
+ To add attachments to a note is rather tricky when done manually as it involves separate file uploads to Amazon S3 and sending
202
+ confirmations back to 4me.
203
+
204
+ To make it easy, a special `attachments` parameter can be added when using the `post` or `put` method when the `note` field is available.
205
+
206
+ ```
207
+ response = Sdk4me::Client.new.put('requests/416621', {
208
+ status: 'waiting_for_customer',
209
+ note: 'Please complete the attached forms and reassign the request back to us.',
210
+ attachments: ['/tmp/forms/Inventory.xls', '/tmp/forms/PersonalData.xls']
211
+ })
212
+ ```
213
+
214
+ If an attachment upload fails, the errors are logged but the `post` or `put` request will still be sent to 4me without the
215
+ failed attachments. To receive exceptions add `attachments_exception: true` to the data.
216
+
217
+ ```
218
+ begin
219
+ response = Sdk4me::Client.new.put('requests/416621', {
220
+ status: 'waiting_for_customer',
221
+ note: 'Please complete the attached forms and reassign the request back to us.',
222
+ attachments: ['/tmp/forms/Inventory.xls', '/tmp/forms/PersonalData.xls']
223
+ })
224
+ if response.valid?
225
+ puts "Request #{response[:id]} updated and attachments added to the note"
226
+ else
227
+ puts "Update of request failed: #{response.message}"
228
+ end
229
+ catch Sdk4me::UploadFailed => ex
230
+ puts "Could not upload an attachment: #{ex.message}"
231
+ end
232
+ ```
233
+
234
+ ### Importing CSV files
235
+
236
+ 4me also provides an [Import API](http://developer.4me.com/v1/import/). The 4me SDK Client can be used to upload files to that API.
237
+
238
+ ```
239
+ response = Sdk4me::Client.new.import('\tmp\people.csv', 'people')
240
+ if response.valid?
241
+ puts "Import queued with token #{response[:token]}"
242
+ else
243
+ puts "Import upload failed: #{response.message}"
244
+ end
245
+
246
+ ```
247
+
248
+ The second argument contains the [import type](http://developer.4me.com/v1/import/#parameters).
249
+
250
+ It is also possible to [monitor the progress](http://developer.4me.com/v1/import/#import-progress) of the import and block until the import is complete. In that case you will need to add some exception handling to your code.
251
+
252
+ ```
253
+ begin
254
+ response = Sdk4me::Client.new.import('\tmp\people.csv', 'people', true)
255
+ puts response[:state]
256
+ puts response[:results]
257
+ puts response[:message]
258
+ catch Sdk4me::UploadFailed => ex
259
+ puts "Could not upload the people import file: #{ex.message}"
260
+ catch Sdk4me::Exception => ex
261
+ puts "Unable to monitor progress of the people import: #{ex.message}"
262
+ end
263
+ ```
264
+
265
+ Note that blocking for the import to finish is required when you import multiple CSVs that are dependent on each other.
266
+
267
+
268
+ ### Exporting CSV files
269
+
270
+ 4me also provides an [Export API](http://developer.4me.com/v1/export/). The 4me SDK Client can be used to download (zipped) CSV files using that API.
271
+
272
+ ```
273
+ response = Sdk4me::Client.new.export(['people', 'people_contact_details'], DateTime.new(2012,03,30,23,00,00))
274
+ if response.valid?
275
+ puts "Export queued with token #{response[:token]}"
276
+ else
277
+ puts "Export failed: #{response.message}"
278
+ end
279
+
280
+ ```
281
+
282
+ The first argument contains the [export types](http://developer.4me.com/v1/export/#parameters).
283
+ The second argument is optional and limits the export to all changed records since the given time.
284
+
285
+ It is also possible to [monitor the progress](http://developer.4me.com/v1/export/#export-progress) of the export and block until the export is complete. In that case you will need to add some exception handling to your code.
286
+
287
+ ```
288
+ require 'open-uri'
289
+
290
+ begin
291
+ response = Sdk4me::Client.new.export(['people', 'people_contact_details'], nil, true)
292
+ puts response[:state]
293
+ # write the export file to disk
294
+ File.open('/tmp/export.zip', 'wb') { |f| f.write(open(response[:url]).read) }
295
+ catch Sdk4me::UploadFailed => ex
296
+ puts "Could not queue the people export: #{ex.message}"
297
+ catch Sdk4me::Exception => ex
298
+ puts "Unable to monitor progress of the people export: #{ex.message}"
299
+ end
300
+ ```
301
+
302
+ Note that blocking for the export to finish is recommended as you will get direct access to the exported file.
303
+
304
+
305
+ ### Blocking
306
+
307
+ By default all actions on the 4me SDK Client will block until the 4me API is accessible, see the _max_retry_time_ option in the [configuration](#global-configuration). This is especially helpfull for flaky internet connections.
308
+
309
+ By setting the _block_at_rate_limit_ to `true` in the [configuration](#global-configuration) all actions will also block in case the [rate limit](http://developer.4me.com/v1/#rate-limiting) is reached. The action is retried every 5 minutes until the [rate limit](http://developer.4me.com/v1/#rate-limiting) is lifted again, which might take up to 1 hour.
310
+
311
+
312
+ ### Exception handling
313
+
314
+ The standard methods `get`, `post`, `put` and `delete` will always return a Response with an [error message](http://developer.4me.com/v1/#http-status-codes) in case something went wrong.
315
+
316
+ By calling `response.valid?` you will know if the action succeeded or not, and `response.message` provides additinal information in case the response was invalid.
317
+
318
+ ```
319
+ response = Sdk4me::Client.new.get('organizations/1a2b')
320
+ puts response.valid?
321
+ puts response.message
322
+ ```
323
+
324
+ The methods `each` and `import` may throw an `Sdk4me::Exception` in case something failed, see the examples above.