pushradar 1.0.2 → 1.8.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 +4 -4
- data/.gitignore +10 -10
- data/.idea/.rakeTasks +5 -5
- data/.idea/PushRadarRuby.iml +12 -12
- data/.idea/inspectionProfiles/Project_Default.xml +5 -5
- data/.idea/misc.xml +3 -3
- data/.idea/modules.xml +7 -7
- data/.idea/vcs.xml +5 -5
- data/.idea/workspace.xml +666 -665
- data/CHANGELOG.md +5 -0
- data/Gemfile +4 -4
- data/LICENSE +20 -20
- data/PushRadar.gemspec +25 -25
- data/README.md +79 -65
- data/VERSION +1 -1
- data/bin/console +5 -5
- data/bin/setup +5 -5
- data/lib/PushRadar/APIClient.rb +4 -4
- data/lib/PushRadar/Targeting.rb +14 -42
- data/lib/PushRadar/Utils.rb +0 -12
- data/lib/PushRadar/version.rb +2 -2
- data/lib/PushRadar.rb +383 -390
- metadata +2 -2
data/lib/PushRadar.rb
CHANGED
@@ -1,391 +1,384 @@
|
|
1
|
-
require 'PushRadar/version'
|
2
|
-
require 'PushRadar/Targeting'
|
3
|
-
require 'PushRadar/APIClient'
|
4
|
-
require 'json'
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
#
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
#
|
30
|
-
api_secret
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
@is_unit_test_mode =
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
# Targets the notification to clients currently located in the given
|
83
|
-
def
|
84
|
-
|
85
|
-
#
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
# Allow method chaining
|
102
|
-
self
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
#
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
#
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
#
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
#
|
300
|
-
def
|
301
|
-
|
302
|
-
#
|
303
|
-
if
|
304
|
-
raise '
|
305
|
-
end
|
306
|
-
|
307
|
-
#
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
#
|
321
|
-
data.
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
#
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
#
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
end
|
385
|
-
|
386
|
-
# Set which methods are private
|
387
|
-
private :reset_targeting
|
388
|
-
|
389
|
-
end
|
390
|
-
|
1
|
+
require 'PushRadar/version'
|
2
|
+
require 'PushRadar/Targeting'
|
3
|
+
require 'PushRadar/APIClient'
|
4
|
+
require 'json'
|
5
|
+
require 'digest/md5'
|
6
|
+
|
7
|
+
module PushRadar
|
8
|
+
|
9
|
+
# A realtime push notifications API service for the web, featuring advanced targeting
|
10
|
+
class Radar
|
11
|
+
|
12
|
+
# Creates a new instance of PushRadar with the specified API secret
|
13
|
+
def initialize(api_secret)
|
14
|
+
|
15
|
+
# Initialize data
|
16
|
+
@data = {}
|
17
|
+
|
18
|
+
# Reset the targeting options
|
19
|
+
reset_targeting
|
20
|
+
|
21
|
+
# Check that the API secret is a string
|
22
|
+
unless api_secret.is_a?(String)
|
23
|
+
raise 'The API secret must be a string value.'
|
24
|
+
end
|
25
|
+
|
26
|
+
# Trim the API secret
|
27
|
+
api_secret.strip!
|
28
|
+
|
29
|
+
# If we are running unit tests, set the unit test mode flag and skip the PushRadar API client initialisation
|
30
|
+
if api_secret == 'test-secret'
|
31
|
+
@is_unit_test_mode = true
|
32
|
+
return
|
33
|
+
else
|
34
|
+
@is_unit_test_mode = false
|
35
|
+
end
|
36
|
+
|
37
|
+
# Check that the API secret starts with sk_
|
38
|
+
unless api_secret.start_with?('sk_')
|
39
|
+
raise 'API secret invalid. You can view your PushRadar API secret at https://dashboard.pushradar.com/api'
|
40
|
+
end
|
41
|
+
|
42
|
+
# Make a new instance of a PushRadar API client with the specified API secret
|
43
|
+
@api_client = APIClient.new(api_secret)
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
# Targets the notification to clients currently using the given browser
|
48
|
+
def target_browser(browser)
|
49
|
+
|
50
|
+
# Add the browser to the list of target browsers
|
51
|
+
@targeting.target_browser browser
|
52
|
+
|
53
|
+
# Allow method chaining
|
54
|
+
self
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# Targets the notification to clients currently using any of the given browsers
|
59
|
+
def target_browsers(*browsers)
|
60
|
+
|
61
|
+
# Target each browser
|
62
|
+
browsers.each {|x|
|
63
|
+
target_browser x
|
64
|
+
}
|
65
|
+
|
66
|
+
# Allow method chaining
|
67
|
+
self
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
# Targets the notification to clients currently located in the given country
|
72
|
+
def target_country(country_code)
|
73
|
+
|
74
|
+
# Add the country to the list of target countries
|
75
|
+
@targeting.target_country country_code
|
76
|
+
|
77
|
+
# Allow method chaining
|
78
|
+
self
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
# Targets the notification to clients currently located in any of the given countries
|
83
|
+
def target_countries(*country_codes)
|
84
|
+
|
85
|
+
# Target each country
|
86
|
+
country_codes.each {|x|
|
87
|
+
target_country x
|
88
|
+
}
|
89
|
+
|
90
|
+
# Allow method chaining
|
91
|
+
self
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
# Targets the notification to clients currently located in Asia
|
96
|
+
def target_asia
|
97
|
+
|
98
|
+
# Target the continent
|
99
|
+
@targeting.target_continent('AS')
|
100
|
+
|
101
|
+
# Allow method chaining
|
102
|
+
self
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# Targets the notification to clients currently located in Africa
|
107
|
+
def target_africa
|
108
|
+
|
109
|
+
# Target the continent
|
110
|
+
@targeting.target_continent('AF')
|
111
|
+
|
112
|
+
# Allow method chaining
|
113
|
+
self
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
# Targets the notification to clients currently located in Antarctica
|
118
|
+
def target_antarctica
|
119
|
+
|
120
|
+
# Target the continent
|
121
|
+
@targeting.target_continent('AN')
|
122
|
+
|
123
|
+
# Allow method chaining
|
124
|
+
self
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
# Targets the notification to clients currently located in Europe
|
129
|
+
def target_europe
|
130
|
+
|
131
|
+
# Target the continent
|
132
|
+
@targeting.target_continent('EU')
|
133
|
+
|
134
|
+
# Allow method chaining
|
135
|
+
self
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
# Targets the notification to clients currently located in North America
|
140
|
+
def target_north_america
|
141
|
+
|
142
|
+
# Target the continent
|
143
|
+
@targeting.target_continent('NA')
|
144
|
+
|
145
|
+
# Allow method chaining
|
146
|
+
self
|
147
|
+
|
148
|
+
end
|
149
|
+
|
150
|
+
# Targets the notification to clients currently located in South America
|
151
|
+
def target_south_america
|
152
|
+
|
153
|
+
# Target the continent
|
154
|
+
@targeting.target_continent('SA')
|
155
|
+
|
156
|
+
# Allow method chaining
|
157
|
+
self
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
# Targets the notification to clients currently located in Oceania
|
162
|
+
def target_oceania
|
163
|
+
|
164
|
+
# Target the continent
|
165
|
+
@targeting.target_continent('OC')
|
166
|
+
|
167
|
+
# Allow method chaining
|
168
|
+
self
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
# Targets the notification to clients with the given IP address
|
173
|
+
def target_ip(ip_address)
|
174
|
+
|
175
|
+
# Add the IP address to the list of target IP addresses
|
176
|
+
@targeting.target_ip ip_address
|
177
|
+
|
178
|
+
# Allow method chaining
|
179
|
+
self
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
# Targets the notification to clients with any of the given IP addresses
|
184
|
+
def target_ips(*ip_addresses)
|
185
|
+
|
186
|
+
# Target each IP address
|
187
|
+
ip_addresses.each {|x|
|
188
|
+
target_ip x
|
189
|
+
}
|
190
|
+
|
191
|
+
# Allow method chaining
|
192
|
+
self
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
# Targets the notification to clients who have taken the given action
|
197
|
+
def target_action(action)
|
198
|
+
|
199
|
+
# Add the action to the list of target actions
|
200
|
+
@targeting.target_action action
|
201
|
+
|
202
|
+
# Allow method chaining
|
203
|
+
self
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
# Targets the notification to clients who have taken any of the given actions
|
208
|
+
def target_actions(*actions)
|
209
|
+
|
210
|
+
# Target each action
|
211
|
+
actions.each {|x|
|
212
|
+
target_action x
|
213
|
+
}
|
214
|
+
|
215
|
+
# Allow method chaining
|
216
|
+
self
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
# Targets the notification to clients who have not taken the given action
|
221
|
+
def target_not_action(action)
|
222
|
+
|
223
|
+
# Add the action to the list of target "not" actions
|
224
|
+
@targeting.target_not_action action
|
225
|
+
|
226
|
+
# Allow method chaining
|
227
|
+
self
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
# Targets the notification to clients who have not taken any of the given actions
|
232
|
+
def target_not_actions(*actions)
|
233
|
+
|
234
|
+
# Target each action
|
235
|
+
actions.each {|x|
|
236
|
+
target_not_action x
|
237
|
+
}
|
238
|
+
|
239
|
+
# Allow method chaining
|
240
|
+
self
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
# Targets the notification to a specific user (identified by their user ID)
|
245
|
+
def target_user(user_id)
|
246
|
+
|
247
|
+
# Target the user
|
248
|
+
@targeting.target_user user_id
|
249
|
+
|
250
|
+
# Allow method chaining
|
251
|
+
self
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
# Targets the notification to specific users (identified by their user IDs)
|
256
|
+
def target_users(*user_ids)
|
257
|
+
|
258
|
+
# Target the user IDs
|
259
|
+
user_ids.each {|x|
|
260
|
+
target_user x
|
261
|
+
}
|
262
|
+
|
263
|
+
# Allow method chaining
|
264
|
+
self
|
265
|
+
|
266
|
+
end
|
267
|
+
|
268
|
+
# Adds a data item to the list of data items
|
269
|
+
def add_data_item(key, value)
|
270
|
+
|
271
|
+
# Make sure the key is not empty
|
272
|
+
if key == ''
|
273
|
+
raise 'The key provided cannot be empty.'
|
274
|
+
end
|
275
|
+
|
276
|
+
# Add the data item
|
277
|
+
unless @data.keys.include?(key)
|
278
|
+
@data[key] = value
|
279
|
+
end
|
280
|
+
|
281
|
+
# Allow method chaining
|
282
|
+
self
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
# Adds multiple data items to the list of data items
|
287
|
+
def add_data_items(data = {})
|
288
|
+
|
289
|
+
# Add the data items
|
290
|
+
data.keys.each {|x|
|
291
|
+
add_data_item x, data[x]
|
292
|
+
}
|
293
|
+
|
294
|
+
# Allow method chaining
|
295
|
+
self
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
# Broadcasts data on the channel specified
|
300
|
+
def broadcast(channel, data = {})
|
301
|
+
|
302
|
+
# If we are running unit tests, throw an exception
|
303
|
+
if @is_unit_test_mode
|
304
|
+
raise 'Unit testing of the broadcast() method is not supported.'
|
305
|
+
end
|
306
|
+
|
307
|
+
# Trim the channel name
|
308
|
+
channel.strip!
|
309
|
+
|
310
|
+
# Check whether data has been provided
|
311
|
+
if data.length == 0 && @data.length == 0
|
312
|
+
raise 'There is no data to broadcast.'
|
313
|
+
end
|
314
|
+
|
315
|
+
# Check whether the channel name contains spaces
|
316
|
+
if channel.include? ' '
|
317
|
+
raise "The channel name cannot contain spaces. By convention, channel names are alphanumerical and lowercase, with optional dashes (e.g. 'test-channel')."
|
318
|
+
end
|
319
|
+
|
320
|
+
# Use the stored data if the data parameter is empty
|
321
|
+
if data.length == 0
|
322
|
+
data = @data
|
323
|
+
else
|
324
|
+
data.keys.each {|x|
|
325
|
+
@data[x] = data[x]
|
326
|
+
}
|
327
|
+
data = @data
|
328
|
+
end
|
329
|
+
|
330
|
+
# Initialize the hash of data to send to the server
|
331
|
+
data_to_send = {
|
332
|
+
notification: {
|
333
|
+
channel: channel,
|
334
|
+
data: data,
|
335
|
+
userIDs: @targeting.instance_variable_get('@target_user_ids'),
|
336
|
+
actions: @targeting.instance_variable_get('@target_actions'),
|
337
|
+
notActions: @targeting.instance_variable_get('@target_not_actions'),
|
338
|
+
continents: @targeting.instance_variable_get('@target_continents'),
|
339
|
+
ipAddresses: @targeting.instance_variable_get('@target_countries'),
|
340
|
+
countries: @targeting.instance_variable_get('@target_ips'),
|
341
|
+
browsers: @targeting.instance_variable_get('@target_browsers'),
|
342
|
+
}.to_json
|
343
|
+
}
|
344
|
+
|
345
|
+
# Broadcast the notification
|
346
|
+
@api_client.post('/broadcast', data_to_send)
|
347
|
+
|
348
|
+
# Reset the targeting options
|
349
|
+
reset_targeting
|
350
|
+
|
351
|
+
end
|
352
|
+
|
353
|
+
def channel_auth(channel)
|
354
|
+
|
355
|
+
# Trim the channel name
|
356
|
+
channel.strip!
|
357
|
+
|
358
|
+
unless (channel.start_with? "private-") || (channel.start_with? "presence-")
|
359
|
+
raise "Channel authentication can only be used with private or presence channels."
|
360
|
+
end
|
361
|
+
|
362
|
+
# Generate the channel authentication token
|
363
|
+
channel_auth_token = "channel_auth_token_" + Digest::MD5.hexdigest(channel) + "." + (0...8).map { (65 + rand(26)).chr }.join
|
364
|
+
|
365
|
+
# Broadcast the notification
|
366
|
+
@api_client.post('/channel-auth', {
|
367
|
+
authToken: channel_auth_token
|
368
|
+
})
|
369
|
+
|
370
|
+
channel_auth_token
|
371
|
+
|
372
|
+
end
|
373
|
+
|
374
|
+
# Resets the targeting options
|
375
|
+
def reset_targeting
|
376
|
+
@targeting = Targeting.new
|
377
|
+
end
|
378
|
+
|
379
|
+
# Set which methods are private
|
380
|
+
private :reset_targeting
|
381
|
+
|
382
|
+
end
|
383
|
+
|
391
384
|
end
|