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