sailthru-client-notest 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.
- data/README.md +13 -0
- data/lib/sailthru.rb +869 -0
- metadata +81 -0
data/README.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
sailthru-ruby-client
|
2
|
+
====================
|
3
|
+
|
4
|
+
For installation instructions, documentation, and examples please visit:
|
5
|
+
[http://getstarted.sailthru.com/developers/api-libraries/ruby](http://getstarted.sailthru.com/developers/api-libraries/ruby)
|
6
|
+
|
7
|
+
A simple client library to remotely access the `Sailthru REST API` as per [http://getstarted.sailthru.com/developers/api](http://getstarted.sailthru.com/developers/api)
|
8
|
+
|
9
|
+
By default, it will make request in `JSON` format.
|
10
|
+
|
11
|
+
### Installing from rubygems.org (Tested with Ruby 1.8.7)
|
12
|
+
$ gem install sailthru-client
|
13
|
+
|
data/lib/sailthru.rb
ADDED
@@ -0,0 +1,869 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/https'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'cgi'
|
6
|
+
require 'json'
|
7
|
+
require 'digest/md5'
|
8
|
+
require 'net/http/post/multipart'
|
9
|
+
|
10
|
+
module Sailthru
|
11
|
+
|
12
|
+
Version = VERSION = '1.15'
|
13
|
+
|
14
|
+
class SailthruClientException < Exception
|
15
|
+
end
|
16
|
+
|
17
|
+
module Helpers
|
18
|
+
# params:
|
19
|
+
# params, Hash
|
20
|
+
# returns:
|
21
|
+
# Array, values of each item in the Hash (and nested hashes)
|
22
|
+
#
|
23
|
+
# Extracts the values of a set of parameters, recursing into nested assoc arrays.
|
24
|
+
def extract_param_values(params)
|
25
|
+
values = []
|
26
|
+
params.each do |k, v|
|
27
|
+
if v.class == Hash
|
28
|
+
values.concat extract_param_values(v)
|
29
|
+
elsif v.class == Array
|
30
|
+
temp_hash = Hash.new()
|
31
|
+
v.each_with_index do |v_,i_|
|
32
|
+
temp_hash[i_.to_s] = v_
|
33
|
+
end
|
34
|
+
values.concat extract_param_values(temp_hash)
|
35
|
+
else
|
36
|
+
values.push v.to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return values
|
40
|
+
end
|
41
|
+
|
42
|
+
# params:
|
43
|
+
# params, Hash
|
44
|
+
# secret, String
|
45
|
+
# returns:
|
46
|
+
# String
|
47
|
+
#
|
48
|
+
# Returns the unhashed signature string (secret + sorted list of param values) for an API call.
|
49
|
+
def get_signature_string(params, secret)
|
50
|
+
return secret + extract_param_values(params).sort.join("")
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# params:
|
55
|
+
# params, Hash
|
56
|
+
# secret, String
|
57
|
+
# returns:
|
58
|
+
# String
|
59
|
+
#
|
60
|
+
# Returns an MD5 hash of the signature string for an API call.
|
61
|
+
def get_signature_hash(params, secret)
|
62
|
+
Digest::MD5.hexdigest(get_signature_string(params, secret)).to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Flatten nested hash for GET / POST request.
|
67
|
+
def flatten_nested_hash(hash, brackets = true)
|
68
|
+
f = {}
|
69
|
+
hash.each do |key, value|
|
70
|
+
_key = brackets ? "[#{key}]" : key.to_s
|
71
|
+
if value.class == Hash
|
72
|
+
flatten_nested_hash(value).each do |k, v|
|
73
|
+
f["#{_key}#{k}"] = v
|
74
|
+
end
|
75
|
+
elsif value.class == Array
|
76
|
+
temp_hash = Hash.new()
|
77
|
+
value.each_with_index do |v, i|
|
78
|
+
temp_hash[i.to_s] = v
|
79
|
+
end
|
80
|
+
flatten_nested_hash(temp_hash).each do |k, v|
|
81
|
+
f["#{_key}#{k}"] = v
|
82
|
+
end
|
83
|
+
|
84
|
+
else
|
85
|
+
f[_key] = value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
return f
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
class SailthruClient
|
94
|
+
|
95
|
+
include Helpers
|
96
|
+
|
97
|
+
attr_accessor :verify_ssl
|
98
|
+
|
99
|
+
# params:
|
100
|
+
# api_key, String
|
101
|
+
# secret, String
|
102
|
+
# api_uri, String
|
103
|
+
#
|
104
|
+
# Instantiate a new client; constructor optionally takes overrides for key/secret/uri and proxy server settings.
|
105
|
+
def initialize(api_key, secret, api_uri=nil, proxy_host=nil, proxy_port=nil)
|
106
|
+
@api_key = api_key
|
107
|
+
@secret = secret
|
108
|
+
@api_uri = if api_uri.nil? then 'https://api.sailthru.com' else api_uri end
|
109
|
+
@proxy_host = proxy_host
|
110
|
+
@proxy_port = proxy_port
|
111
|
+
@verify_ssl = true
|
112
|
+
end
|
113
|
+
|
114
|
+
# params:
|
115
|
+
# template_name, String
|
116
|
+
# email, String
|
117
|
+
# replacements, Hash
|
118
|
+
# options, Hash
|
119
|
+
# replyto: override Reply-To header
|
120
|
+
# test: send as test email (subject line will be marked, will not count towards stats)
|
121
|
+
# schedule_time, Date
|
122
|
+
# returns:
|
123
|
+
# Hash, response data from server
|
124
|
+
#
|
125
|
+
# Send a transactional email, or schedule one for the near future
|
126
|
+
# http://docs.sailthru.com/api/send
|
127
|
+
def send(template_name, email, vars={}, options = {}, schedule_time = nil)
|
128
|
+
warn "[DEPRECATION] `send` is deprecated. Please use `send_email` instead."
|
129
|
+
send_email(template_name, email, vars={}, options = {}, schedule_time = nil)
|
130
|
+
end
|
131
|
+
|
132
|
+
# params:
|
133
|
+
# template_name, String
|
134
|
+
# email, String
|
135
|
+
# vars, Hash
|
136
|
+
# options, Hash
|
137
|
+
# replyto: override Reply-To header
|
138
|
+
# test: send as test email (subject line will be marked, will not count towards stats)
|
139
|
+
# returns:
|
140
|
+
# Hash, response data from server
|
141
|
+
def send_email(template_name, email, vars={}, options = {}, schedule_time = nil)
|
142
|
+
post = {}
|
143
|
+
post[:template] = template_name
|
144
|
+
post[:email] = email
|
145
|
+
post[:vars] = vars if vars.length >= 1
|
146
|
+
post[:options] = options if options.length >= 1
|
147
|
+
post[:schedule_time] = schedule_time if !schedule_time.nil?
|
148
|
+
return self.api_post(:send, post)
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
def multi_send(template_name, emails, vars={}, options = {}, schedule_time = nil, evars = {})
|
153
|
+
post = {}
|
154
|
+
post[:template] = template_name
|
155
|
+
post[:email] = emails
|
156
|
+
post[:vars] = vars if vars.length >= 1
|
157
|
+
post[:options] = options if options.length >= 1
|
158
|
+
post[:schedule_time] = schedule_time if !schedule_time.nil?
|
159
|
+
post[:evars] = evars if evars.length >= 1
|
160
|
+
return self.api_post(:send, post)
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
# params:
|
165
|
+
# send_id, Fixnum
|
166
|
+
# returns:
|
167
|
+
# Hash, response data from server
|
168
|
+
#
|
169
|
+
# Get the status of a send.
|
170
|
+
def get_send(send_id)
|
171
|
+
self.api_get(:send, {:send_id => send_id.to_s})
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
def cancel_send(send_id)
|
176
|
+
self.api_delete(:send, {:send_id => send_id.to_s})
|
177
|
+
end
|
178
|
+
|
179
|
+
# params:
|
180
|
+
# name, String
|
181
|
+
# list, String
|
182
|
+
# schedule_time, String
|
183
|
+
# from_name, String
|
184
|
+
# from_email, String
|
185
|
+
# subject, String
|
186
|
+
# content_html, String
|
187
|
+
# content_text, String
|
188
|
+
# options, Hash
|
189
|
+
# returns:
|
190
|
+
# Hash, response data from server
|
191
|
+
#
|
192
|
+
# Schedule a mass mail blast
|
193
|
+
def schedule_blast(name, list, schedule_time, from_name, from_email, subject, content_html, content_text, options = {})
|
194
|
+
post = options ? options : {}
|
195
|
+
post[:name] = name
|
196
|
+
post[:list] = list
|
197
|
+
post[:schedule_time] = schedule_time
|
198
|
+
post[:from_name] = from_name
|
199
|
+
post[:from_email] = from_email
|
200
|
+
post[:subject] = subject
|
201
|
+
post[:content_html] = content_html
|
202
|
+
post[:content_text] = content_text
|
203
|
+
api_post(:blast, post)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Schedule a mass mail blast from template
|
207
|
+
def schedule_blast_from_template(template, list, schedule_time, options={})
|
208
|
+
post = options ? options : {}
|
209
|
+
post[:copy_template] = template
|
210
|
+
post[:list] = list
|
211
|
+
post[:schedule_time] = schedule_time
|
212
|
+
api_post(:blast, post)
|
213
|
+
end
|
214
|
+
|
215
|
+
# Schedule a mass mail blast from previous blast
|
216
|
+
def schedule_blast_from_blast(blast_id, schedule_time, options={})
|
217
|
+
post = options ? options : {}
|
218
|
+
post[:copy_blast] = blast_id
|
219
|
+
#post[:name] = name
|
220
|
+
post[:schedule_time] = schedule_time
|
221
|
+
api_post(:blast, post)
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
# params
|
226
|
+
# blast_id, Fixnum | String
|
227
|
+
# name, String
|
228
|
+
# list, String
|
229
|
+
# schedule_time, String
|
230
|
+
# from_name, String
|
231
|
+
# from_email, String
|
232
|
+
# subject, String
|
233
|
+
# content_html, String
|
234
|
+
# content_text, String
|
235
|
+
# options, hash
|
236
|
+
#
|
237
|
+
# updates existing blast
|
238
|
+
def update_blast(blast_id, name = nil, list = nil, schedule_time = nil, from_name = nil, from_email = nil, subject = nil, content_html = nil, content_text = nil, options = {})
|
239
|
+
data = options ? options : {}
|
240
|
+
data[:blast_id] = blast_id
|
241
|
+
if name != nil
|
242
|
+
data[:name] = name
|
243
|
+
end
|
244
|
+
if list != nil
|
245
|
+
data[:list] = list
|
246
|
+
end
|
247
|
+
if schedule_time != nil
|
248
|
+
data[:schedule_time] = schedule_time
|
249
|
+
end
|
250
|
+
if from_name != nil
|
251
|
+
data[:from_name] = from_name
|
252
|
+
end
|
253
|
+
if from_email != nil
|
254
|
+
data[:from_email] = from_email
|
255
|
+
end
|
256
|
+
if subject != nil
|
257
|
+
data[:subject] = subject
|
258
|
+
end
|
259
|
+
if content_html != nil
|
260
|
+
data[:content_html] = content_html
|
261
|
+
end
|
262
|
+
if content_text != nil
|
263
|
+
data[:content_text] = content_text
|
264
|
+
end
|
265
|
+
api_post(:blast, data)
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
# params:
|
270
|
+
# blast_id, Fixnum | String
|
271
|
+
# options, hash
|
272
|
+
# returns:
|
273
|
+
# Hash, response data from server
|
274
|
+
#
|
275
|
+
# Get information on a previously scheduled email blast
|
276
|
+
def get_blast(blast_id, options={})
|
277
|
+
options[:blast_id] = blast_id.to_s
|
278
|
+
api_get(:blast, options)
|
279
|
+
end
|
280
|
+
|
281
|
+
# params:
|
282
|
+
# blast_id, Fixnum | String
|
283
|
+
#
|
284
|
+
# Cancel a scheduled Blast
|
285
|
+
def cancel_blast(blast_id)
|
286
|
+
api_post(:blast, {:blast_id => blast_id, :schedule_time => ''})
|
287
|
+
end
|
288
|
+
|
289
|
+
# params:
|
290
|
+
# blast_id, Fixnum | String
|
291
|
+
#
|
292
|
+
# Delete a Blast
|
293
|
+
def delete_blast(blast_id)
|
294
|
+
api_delete(:blast, {:blast_id => blast_id})
|
295
|
+
end
|
296
|
+
|
297
|
+
# params:
|
298
|
+
# email, String
|
299
|
+
# returns:
|
300
|
+
# Hash, response data from server
|
301
|
+
#
|
302
|
+
# Return information about an email address, including replacement vars and lists.
|
303
|
+
def get_email(email)
|
304
|
+
api_get(:email, {:email => email})
|
305
|
+
end
|
306
|
+
|
307
|
+
# params:
|
308
|
+
# email, String
|
309
|
+
# vars, Hash
|
310
|
+
# lists, Hash mapping list name => 1 for subscribed, 0 for unsubscribed
|
311
|
+
# options, Hash mapping optional parameters
|
312
|
+
# returns:
|
313
|
+
# Hash, response data from server
|
314
|
+
#
|
315
|
+
# Set replacement vars and/or list subscriptions for an email address.
|
316
|
+
def set_email(email, vars = {}, lists = {}, templates = {}, options = {})
|
317
|
+
data = options
|
318
|
+
data[:email] = email
|
319
|
+
data[:vars] = vars unless vars.empty?
|
320
|
+
data[:lists] = lists unless lists.empty?
|
321
|
+
data[:templates] = templates unless templates.empty?
|
322
|
+
self.api_post(:email, data)
|
323
|
+
end
|
324
|
+
|
325
|
+
# params:
|
326
|
+
# new_email, String
|
327
|
+
# old_email, String
|
328
|
+
# options, Hash mapping optional parameters
|
329
|
+
# returns:
|
330
|
+
# Hash of response data.
|
331
|
+
#
|
332
|
+
# change a user's email address.
|
333
|
+
def change_email(new_email, old_email, options = {})
|
334
|
+
data = options
|
335
|
+
data[:email] = new_email
|
336
|
+
data[:change_email] = old_email
|
337
|
+
self.api_post(:email, data)
|
338
|
+
end
|
339
|
+
|
340
|
+
# params:
|
341
|
+
# template_name, String
|
342
|
+
# returns:
|
343
|
+
# Hash of response data.
|
344
|
+
#
|
345
|
+
# Get a template.
|
346
|
+
def get_template(template_name)
|
347
|
+
self.api_get(:template, {:template => template_name})
|
348
|
+
end
|
349
|
+
|
350
|
+
|
351
|
+
# params:
|
352
|
+
# template_name, String
|
353
|
+
# template_fields, Hash
|
354
|
+
# returns:
|
355
|
+
# Hash containg response from the server.
|
356
|
+
#
|
357
|
+
# Save a template.
|
358
|
+
def save_template(template_name, template_fields)
|
359
|
+
data = template_fields
|
360
|
+
data[:template] = template_name
|
361
|
+
self.api_post(:template, data)
|
362
|
+
end
|
363
|
+
|
364
|
+
# params:
|
365
|
+
# template_name, String
|
366
|
+
# returns:
|
367
|
+
# Hash of response data.
|
368
|
+
#
|
369
|
+
# Delete a template.
|
370
|
+
def delete_template(template_name)
|
371
|
+
self.api_delete(:template, {:template => template_name})
|
372
|
+
end
|
373
|
+
|
374
|
+
|
375
|
+
# params:
|
376
|
+
# params, Hash
|
377
|
+
# request, String
|
378
|
+
# returns:
|
379
|
+
# TrueClass or FalseClass, Returns true if the incoming request is an authenticated verify post.
|
380
|
+
def receive_verify_post(params, request)
|
381
|
+
if request.post?
|
382
|
+
[:action, :email, :send_id, :sig].each { |key| return false unless params.has_key?(key) }
|
383
|
+
|
384
|
+
return false unless params[:action] == :verify
|
385
|
+
|
386
|
+
sig = params.delete(:sig)
|
387
|
+
return false unless sig == get_signature_hash(params, @secret)
|
388
|
+
|
389
|
+
_send = self.get_send(params[:send_id])
|
390
|
+
return false unless _send.has_key?(:email)
|
391
|
+
|
392
|
+
return false unless _send[:email] == params[:email]
|
393
|
+
|
394
|
+
return true
|
395
|
+
else
|
396
|
+
return false
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# params:
|
401
|
+
# params, Hash
|
402
|
+
# request, String
|
403
|
+
# returns:
|
404
|
+
# TrueClass or FalseClass, Returns true if the incoming request is an authenticated optout post.
|
405
|
+
def receive_optout_post(params, request)
|
406
|
+
if request.post?
|
407
|
+
[:action, :email, :sig].each { |key| return false unless params.has_key?(key) }
|
408
|
+
|
409
|
+
return false unless params[:action] == :optout
|
410
|
+
|
411
|
+
sig = params.delete(:sig)
|
412
|
+
return false unless sig == get_signature_hash(params, @secret)
|
413
|
+
return true
|
414
|
+
else
|
415
|
+
return false
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
# params:
|
420
|
+
# email, String
|
421
|
+
# items, String
|
422
|
+
# incomplete, Integer
|
423
|
+
# message_id, String
|
424
|
+
# options, Hash
|
425
|
+
# returns:
|
426
|
+
# hash, response from server
|
427
|
+
#
|
428
|
+
# Record that a user has made a purchase, or has added items to their purchase total.
|
429
|
+
def purchase(email, items, incomplete = nil, message_id = nil, options = {})
|
430
|
+
data = options
|
431
|
+
data[:email] = email
|
432
|
+
data[:items] = items
|
433
|
+
|
434
|
+
if incomplete != nil
|
435
|
+
data[:incomplete] = incomplete.to_i
|
436
|
+
end
|
437
|
+
|
438
|
+
if message_id != nil
|
439
|
+
data[:message_id] = message_id
|
440
|
+
end
|
441
|
+
api_post(:purchase, data)
|
442
|
+
end
|
443
|
+
|
444
|
+
|
445
|
+
# <b>DEPRECATED:</b> Please use either stats_list or stats_blast
|
446
|
+
# params:
|
447
|
+
# stat, String
|
448
|
+
#
|
449
|
+
# returns:
|
450
|
+
# hash, response from server
|
451
|
+
# Request various stats from Sailthru.
|
452
|
+
def get_stats(stat)
|
453
|
+
warn "[DEPRECATION] `get_stats` is deprecated. Please use `stats_list` and `stats_blast` instead"
|
454
|
+
api_get(:stats, {:stat => stat})
|
455
|
+
end
|
456
|
+
|
457
|
+
|
458
|
+
# params
|
459
|
+
# list, String
|
460
|
+
# date, String
|
461
|
+
#
|
462
|
+
# returns:
|
463
|
+
# hash, response from server
|
464
|
+
# Retrieve information about your subscriber counts on a particular list, on a particular day.
|
465
|
+
def stats_list(list = nil, date = nil)
|
466
|
+
data = {}
|
467
|
+
if list != nil
|
468
|
+
data[:list] = list
|
469
|
+
end
|
470
|
+
if date != nil
|
471
|
+
data[:date] = date
|
472
|
+
end
|
473
|
+
data[:stat] = 'list'
|
474
|
+
stats(data)
|
475
|
+
end
|
476
|
+
|
477
|
+
|
478
|
+
# params
|
479
|
+
# blast_id, String
|
480
|
+
# start_date, String
|
481
|
+
# end_date, String
|
482
|
+
# options, Hash
|
483
|
+
#
|
484
|
+
# returns:
|
485
|
+
# hash, response from server
|
486
|
+
# Retrieve information about a particular blast or aggregated information from all of blasts over a specified date range
|
487
|
+
def stats_blast(blast_id = nil, start_date = nil, end_date = nil, options = {})
|
488
|
+
data = options
|
489
|
+
if blast_id != nil
|
490
|
+
data[:blast_id] = blast_id
|
491
|
+
end
|
492
|
+
if start_date != nil
|
493
|
+
data[:start_date] = start_date
|
494
|
+
end
|
495
|
+
if end_date != nil
|
496
|
+
data[:end_date] = end_date
|
497
|
+
end
|
498
|
+
data[:stat] = 'blast'
|
499
|
+
stats(data)
|
500
|
+
end
|
501
|
+
|
502
|
+
# params
|
503
|
+
# template, String
|
504
|
+
# start_date, String
|
505
|
+
# end_date, String
|
506
|
+
# options, Hash
|
507
|
+
#
|
508
|
+
# returns:
|
509
|
+
# hash, response from server
|
510
|
+
# Retrieve information about a particular blast or aggregated information from all of blasts over a specified date range
|
511
|
+
def stats_send(template = nil, start_date = nil, end_date = nil, options = {})
|
512
|
+
data = options
|
513
|
+
if template != nil
|
514
|
+
data[:template] = template
|
515
|
+
end
|
516
|
+
if start_date != nil
|
517
|
+
data[:start_date] = start_date
|
518
|
+
end
|
519
|
+
if end_date != nil
|
520
|
+
data[:end_date] = end_date
|
521
|
+
end
|
522
|
+
data[:stat] = 'send'
|
523
|
+
stats(data)
|
524
|
+
end
|
525
|
+
|
526
|
+
|
527
|
+
# params
|
528
|
+
# title, String
|
529
|
+
# url, String
|
530
|
+
# date, String
|
531
|
+
# tags, Array or Comma separated string
|
532
|
+
# vars, Hash
|
533
|
+
#
|
534
|
+
# Push a new piece of content to Sailthru, triggering any applicable alerts.
|
535
|
+
# http://docs.sailthru.com/api/content
|
536
|
+
def push_content(title, url, date = nil, tags = nil, vars = {}, options = {})
|
537
|
+
data = options
|
538
|
+
data[:title] = title
|
539
|
+
data[:url] = url
|
540
|
+
if date != nil
|
541
|
+
data[:date] = date
|
542
|
+
end
|
543
|
+
if tags != nil
|
544
|
+
if tags.class == Array
|
545
|
+
tags = tags.join(',')
|
546
|
+
end
|
547
|
+
data[:tags] = tags
|
548
|
+
end
|
549
|
+
if vars.length > 0
|
550
|
+
data[:vars] = vars
|
551
|
+
end
|
552
|
+
api_post(:content, data)
|
553
|
+
end
|
554
|
+
|
555
|
+
# params
|
556
|
+
# list, String
|
557
|
+
#
|
558
|
+
# Get information about a list.
|
559
|
+
def get_list(list)
|
560
|
+
return api_get(:list, {:list => list})
|
561
|
+
end
|
562
|
+
|
563
|
+
# params
|
564
|
+
#
|
565
|
+
# Get information about all lists
|
566
|
+
def get_lists()
|
567
|
+
return api_get(:list, {})
|
568
|
+
end
|
569
|
+
|
570
|
+
# params
|
571
|
+
# list, String
|
572
|
+
# options, Hash
|
573
|
+
# Create a list, or update a list.
|
574
|
+
def save_list(list, options = {})
|
575
|
+
data = options
|
576
|
+
data[:list] = list
|
577
|
+
return api_post(:list, data)
|
578
|
+
end
|
579
|
+
|
580
|
+
# params
|
581
|
+
# list, String
|
582
|
+
#
|
583
|
+
# Deletes a list
|
584
|
+
def delete_list(list)
|
585
|
+
api_delete(:list, {:list => list})
|
586
|
+
end
|
587
|
+
|
588
|
+
# params
|
589
|
+
# email, String
|
590
|
+
#
|
591
|
+
# get user alert data
|
592
|
+
def get_alert(email)
|
593
|
+
api_get(:alert, {:email => email})
|
594
|
+
end
|
595
|
+
|
596
|
+
# params
|
597
|
+
# email, String
|
598
|
+
# type, String
|
599
|
+
# template, String
|
600
|
+
# _when, String
|
601
|
+
# options, hash
|
602
|
+
#
|
603
|
+
# Add a new alert to a user. You can add either a realtime or a summary alert (daily/weekly).
|
604
|
+
# _when is only required when alert type is weekly or daily
|
605
|
+
def save_alert(email, type, template, _when = nil, options = {})
|
606
|
+
data = options
|
607
|
+
data[:email] = email
|
608
|
+
data[:type] = type
|
609
|
+
data[:template] = template
|
610
|
+
if (type == 'weekly' || type == 'daily')
|
611
|
+
data[:when] = _when
|
612
|
+
end
|
613
|
+
api_post(:alert, data)
|
614
|
+
end
|
615
|
+
|
616
|
+
|
617
|
+
# params
|
618
|
+
# email, String
|
619
|
+
# alert_id, String
|
620
|
+
#
|
621
|
+
# delete user alert
|
622
|
+
def delete_alert(email, alert_id)
|
623
|
+
data = {:email => email, :alert_id => alert_id}
|
624
|
+
api_delete(:alert, data)
|
625
|
+
end
|
626
|
+
|
627
|
+
# Make Stats API Request
|
628
|
+
def stats(data)
|
629
|
+
api_get(:stats, data)
|
630
|
+
end
|
631
|
+
|
632
|
+
# params
|
633
|
+
# job, String
|
634
|
+
# options, hash
|
635
|
+
# report_email, String
|
636
|
+
# postback_url, String
|
637
|
+
# binary_key, String
|
638
|
+
#
|
639
|
+
# interface for making request to job call
|
640
|
+
def process_job(job, options = {}, report_email = nil, postback_url = nil, binary_key = nil)
|
641
|
+
data = options
|
642
|
+
data['job'] = job
|
643
|
+
if !report_email.nil?
|
644
|
+
data['report_email'] = report_email
|
645
|
+
end
|
646
|
+
|
647
|
+
if !postback_url.nil?
|
648
|
+
data['postback_url'] = postback_url
|
649
|
+
end
|
650
|
+
api_post(:job, data, binary_key)
|
651
|
+
end
|
652
|
+
|
653
|
+
# params
|
654
|
+
# emails, String | Array
|
655
|
+
# implementation for import_job
|
656
|
+
def process_import_job(list, emails, report_email = nil, postback_url = nil)
|
657
|
+
data = {}
|
658
|
+
data['list'] = list
|
659
|
+
data['emails'] = Array(emails).join(',')
|
660
|
+
process_job(:import, data, report_email, postback_url)
|
661
|
+
end
|
662
|
+
|
663
|
+
# implementation for import job using file upload
|
664
|
+
def process_import_job_from_file(list, file_path, report_email = nil, postback_url = nil)
|
665
|
+
data = {}
|
666
|
+
data['list'] = list
|
667
|
+
data['file'] = file_path
|
668
|
+
process_job(:import, data, report_email, postback_url, 'file')
|
669
|
+
end
|
670
|
+
|
671
|
+
# implementation for update job using file upload
|
672
|
+
def process_update_job_from_file(file_path, report_email = nil, postback_url = nil)
|
673
|
+
data = {}
|
674
|
+
data['file'] = file_path
|
675
|
+
process_job(:update, data, report_email, postback_url, 'file')
|
676
|
+
end
|
677
|
+
|
678
|
+
# implementation for snapshot job
|
679
|
+
def process_snapshot_job(query = {}, report_email = nil, postback_url = nil)
|
680
|
+
data = {}
|
681
|
+
data['query'] = query
|
682
|
+
process_job(:snapshot, data, report_email, postback_url)
|
683
|
+
end
|
684
|
+
|
685
|
+
# implementation for export list job
|
686
|
+
def process_export_list_job(list, report_email = nil, postback_url = nil)
|
687
|
+
data = {}
|
688
|
+
data['list'] = list
|
689
|
+
process_job(:export_list_data, data, report_email, postback_url)
|
690
|
+
end
|
691
|
+
|
692
|
+
# get status of a job
|
693
|
+
def get_job_status(job_id)
|
694
|
+
api_get(:job, {'job_id' => job_id})
|
695
|
+
end
|
696
|
+
|
697
|
+
# Get user by Sailthru ID
|
698
|
+
def get_user_by_sid(id, fields = {})
|
699
|
+
api_get(:user, {'id' => id, 'fields' => fields})
|
700
|
+
end
|
701
|
+
|
702
|
+
# Get user by specified key
|
703
|
+
def get_user_by_key(id, key, fields = {})
|
704
|
+
data = {
|
705
|
+
'id' => id,
|
706
|
+
'key' => key,
|
707
|
+
'fields' => fields
|
708
|
+
}
|
709
|
+
api_get(:user, data)
|
710
|
+
end
|
711
|
+
|
712
|
+
# Create new user, or update existing user
|
713
|
+
def save_user(id, options = {})
|
714
|
+
data = options
|
715
|
+
data['id'] = id
|
716
|
+
api_post(:user, data)
|
717
|
+
end
|
718
|
+
|
719
|
+
# Perform API GET request
|
720
|
+
def api_get(action, data)
|
721
|
+
api_request(action, data, 'GET')
|
722
|
+
end
|
723
|
+
|
724
|
+
# Perform API POST request
|
725
|
+
def api_post(action, data, binary_key = nil)
|
726
|
+
api_request(action, data, 'POST', binary_key)
|
727
|
+
end
|
728
|
+
|
729
|
+
#Perform API DELETE request
|
730
|
+
def api_delete(action, data)
|
731
|
+
api_request(action, data, 'DELETE')
|
732
|
+
end
|
733
|
+
|
734
|
+
protected
|
735
|
+
|
736
|
+
# params:
|
737
|
+
# action, String
|
738
|
+
# data, Hash
|
739
|
+
# request, String "GET" or "POST"
|
740
|
+
# returns:
|
741
|
+
# Hash
|
742
|
+
#
|
743
|
+
# Perform an API request, using the shared-secret auth hash.
|
744
|
+
#
|
745
|
+
def api_request(action, data, request_type, binary_key = nil)
|
746
|
+
if (!binary_key.nil?)
|
747
|
+
binary_key_data = data[binary_key]
|
748
|
+
data.delete(binary_key)
|
749
|
+
end
|
750
|
+
|
751
|
+
if data[:format].nil? or data[:format] == 'json'
|
752
|
+
data = self.prepare_json_payload(data)
|
753
|
+
else
|
754
|
+
data[:api_key] = @api_key
|
755
|
+
data[:format] ||= 'json'
|
756
|
+
data[:sig] = get_signature_hash(data, @secret)
|
757
|
+
end
|
758
|
+
|
759
|
+
if (!binary_key.nil?)
|
760
|
+
data[binary_key] = binary_key_data
|
761
|
+
end
|
762
|
+
_result = self.http_request("#{@api_uri}/#{action}", data, request_type, binary_key)
|
763
|
+
|
764
|
+
# NOTE: don't do the unserialize here
|
765
|
+
if data[:format] == 'json'
|
766
|
+
begin
|
767
|
+
unserialized = JSON.parse(_result)
|
768
|
+
return unserialized ? unserialized : _result
|
769
|
+
rescue JSON::JSONError => e
|
770
|
+
return {'error' => e}
|
771
|
+
end
|
772
|
+
end
|
773
|
+
return _result
|
774
|
+
end
|
775
|
+
|
776
|
+
# set up our post request
|
777
|
+
def set_up_post_request(uri, data, headers, binary_key = nil)
|
778
|
+
if (!binary_key.nil?)
|
779
|
+
binary_data = data[binary_key]
|
780
|
+
|
781
|
+
if binary_data.is_a?(StringIO)
|
782
|
+
data[binary_key] = UploadIO.new(
|
783
|
+
binary_data, "text/plain"
|
784
|
+
)
|
785
|
+
else
|
786
|
+
data[binary_key] = UploadIO.new(
|
787
|
+
File.open(binary_data), "text/plain"
|
788
|
+
)
|
789
|
+
end
|
790
|
+
|
791
|
+
req = Net::HTTP::Post::Multipart.new(uri.path, data)
|
792
|
+
else
|
793
|
+
req = Net::HTTP::Post.new(uri.path, headers)
|
794
|
+
req.set_form_data(data)
|
795
|
+
end
|
796
|
+
req
|
797
|
+
end
|
798
|
+
|
799
|
+
# params:
|
800
|
+
# uri, String
|
801
|
+
# data, Hash
|
802
|
+
# method, String "GET" or "POST"
|
803
|
+
# returns:
|
804
|
+
# String, body of response
|
805
|
+
def http_request(uri, data, method = 'POST', binary_key = nil)
|
806
|
+
data = flatten_nested_hash(data, false)
|
807
|
+
|
808
|
+
if method != 'POST'
|
809
|
+
uri += "?" + data.map{ |key, value| "#{CGI::escape(key.to_s)}=#{CGI::escape(value.to_s)}" }.join("&")
|
810
|
+
end
|
811
|
+
|
812
|
+
req = nil
|
813
|
+
headers = {"User-Agent" => "Sailthru API Ruby Client #{VERSION}"}
|
814
|
+
|
815
|
+
_uri = URI.parse(uri)
|
816
|
+
|
817
|
+
if method == 'POST'
|
818
|
+
req = self.set_up_post_request(
|
819
|
+
_uri, data, headers, binary_key
|
820
|
+
)
|
821
|
+
|
822
|
+
else
|
823
|
+
request_uri = "#{_uri.path}?#{_uri.query}"
|
824
|
+
if method == 'DELETE'
|
825
|
+
req = Net::HTTP::Delete.new(request_uri, headers)
|
826
|
+
else
|
827
|
+
req = Net::HTTP::Get.new(request_uri, headers)
|
828
|
+
end
|
829
|
+
end
|
830
|
+
|
831
|
+
begin
|
832
|
+
http = Net::HTTP::Proxy(@proxy_host, @proxy_port).new(_uri.host, _uri.port)
|
833
|
+
|
834
|
+
if _uri.scheme == 'https'
|
835
|
+
http.use_ssl = true
|
836
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @verify_ssl != true # some openSSL client doesn't work without doing this
|
837
|
+
end
|
838
|
+
|
839
|
+
response = http.start {
|
840
|
+
http.request(req)
|
841
|
+
}
|
842
|
+
|
843
|
+
rescue Exception => e
|
844
|
+
raise SailthruClientException.new("Unable to open stream: #{_uri}\n#{e}");
|
845
|
+
end
|
846
|
+
|
847
|
+
if response.body
|
848
|
+
return response.body
|
849
|
+
else
|
850
|
+
raise SailthruClientException.new("No response received from stream: #{_uri}")
|
851
|
+
end
|
852
|
+
end
|
853
|
+
|
854
|
+
def http_multipart_request(uri, data)
|
855
|
+
req = Net::HTTP::Post::Multipart.new url.path,
|
856
|
+
"file" => UploadIO.new(data['file'], "application/octet-stream")
|
857
|
+
end
|
858
|
+
|
859
|
+
def prepare_json_payload(data)
|
860
|
+
payload = {
|
861
|
+
:api_key => @api_key,
|
862
|
+
:format => 'json', #<3 XML
|
863
|
+
:json => data.to_json
|
864
|
+
}
|
865
|
+
payload[:sig] = get_signature_hash(payload, @secret)
|
866
|
+
payload
|
867
|
+
end
|
868
|
+
end
|
869
|
+
end
|
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sailthru-client-notest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.2'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Prajwal Tuladhar
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-24 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: multipart-post
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description:
|
47
|
+
email: dyu@sailthru.com
|
48
|
+
executables: []
|
49
|
+
extensions: []
|
50
|
+
extra_rdoc_files:
|
51
|
+
- README.md
|
52
|
+
files:
|
53
|
+
- README.md
|
54
|
+
- lib/sailthru.rb
|
55
|
+
homepage: http://docs.sailthru.com
|
56
|
+
licenses: []
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options:
|
59
|
+
- --main
|
60
|
+
- README.md
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ! '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
requirements: []
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.8.25
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: A simple client library to remotely access the Sailthru REST API.
|
81
|
+
test_files: []
|