urbanairship 3.0.2 → 3.1.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 +2 -0
- data/CHANGELOG +13 -0
- data/README.rst +111 -0
- data/docs/Makefile +192 -0
- data/docs/channel_uninstall.rst +21 -0
- data/docs/conf.py +293 -0
- data/docs/devices.rst +54 -0
- data/docs/examples.rst +118 -0
- data/docs/exceptions.rst +17 -0
- data/docs/index.rst +83 -0
- data/docs/named_user.rst +101 -0
- data/docs/push.rst +416 -0
- data/docs/reports.rst +303 -0
- data/docs/segment.rst +97 -0
- data/docs/tags.rst +49 -0
- data/lib/urbanairship/client.rb +20 -17
- data/lib/urbanairship/common.rb +47 -3
- data/lib/urbanairship/devices/channel_tags.rb +73 -0
- data/lib/urbanairship/devices/channel_uninstall.rb +35 -0
- data/lib/urbanairship/devices/devicelist.rb +61 -0
- data/lib/urbanairship/devices/named_user.rb +87 -0
- data/lib/urbanairship/devices/segment.rb +109 -0
- data/lib/urbanairship/loggable.rb +1 -0
- data/lib/urbanairship/push/audience.rb +1 -0
- data/lib/urbanairship/push/push.rb +12 -18
- data/lib/urbanairship/push/schedule.rb +1 -0
- data/lib/urbanairship/reports/per_push.rb +97 -0
- data/lib/urbanairship/reports/response_statistics.rb +157 -0
- data/lib/urbanairship/version.rb +1 -1
- data/lib/urbanairship.rb +9 -4
- data/urbanairship.gemspec +2 -2
- metadata +44 -25
- data/README.md +0 -96
data/lib/urbanairship/client.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'unirest'
|
2
|
-
require 'urbanairship
|
3
|
-
|
2
|
+
require 'urbanairship'
|
3
|
+
|
4
4
|
|
5
5
|
module Urbanairship
|
6
6
|
class Client
|
@@ -28,10 +28,9 @@ module Urbanairship
|
|
28
28
|
# @param [Object] url Request URL
|
29
29
|
# @param [Object] content_type Content-Type
|
30
30
|
# @param [Object] version API Version
|
31
|
-
# @param [Object] params Parameters
|
32
31
|
# @return [Object] Push Response
|
33
|
-
def send_request(method: required('method'),
|
34
|
-
content_type: nil
|
32
|
+
def send_request(method: required('method'), url: required('url'), body: nil,
|
33
|
+
content_type: nil)
|
35
34
|
req_type = case method
|
36
35
|
when 'GET'
|
37
36
|
:get
|
@@ -45,26 +44,30 @@ module Urbanairship
|
|
45
44
|
fail 'Method was not "GET" "POST" "PUT" or "DELETE"'
|
46
45
|
end
|
47
46
|
|
48
|
-
|
47
|
+
headers = {'User-agent' => 'UARubyLib/' + UA::VERSION}
|
48
|
+
headers['Accept'] = 'application/vnd.urbanairship+json; version=3'
|
49
|
+
|
50
|
+
if content_type
|
51
|
+
headers['Content-type'] = content_type
|
52
|
+
end
|
53
|
+
|
54
|
+
logger.debug("Making #{method} request to #{url}. \n\tHeaders:\n\tcontent-type: #{content_type}\n\tversion=3\nBody:\n\t#{body}")
|
49
55
|
|
50
56
|
response = Unirest.method(req_type).call(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
:password=>@secret
|
59
|
-
},
|
60
|
-
parameters: body
|
57
|
+
url,
|
58
|
+
headers: headers,
|
59
|
+
auth:{
|
60
|
+
:user=>@key,
|
61
|
+
:password=>@secret
|
62
|
+
},
|
63
|
+
parameters: body
|
61
64
|
)
|
62
65
|
|
63
66
|
logger.debug("Received #{response.code} response. Headers:\n\t#{response.headers}\nBody:\n\t#{response.body}")
|
64
67
|
|
65
68
|
Response.check_code(response.code, response)
|
66
69
|
|
67
|
-
{'body'=>response.body, 'code'=>response.code}
|
70
|
+
{'body'=>response.body, 'code'=>response.code, 'headers'=>response.headers}
|
68
71
|
end
|
69
72
|
|
70
73
|
# Create a Push Object
|
data/lib/urbanairship/common.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'urbanairship/loggable'
|
2
2
|
|
3
|
+
|
3
4
|
module Urbanairship
|
4
5
|
# Features mixed in to all classes
|
5
6
|
module Common
|
@@ -13,8 +14,9 @@ module Urbanairship
|
|
13
14
|
DT_FEEDBACK_URL = BASE_URL + '/device_tokens/feedback/'
|
14
15
|
APID_FEEDBACK_URL = BASE_URL + '/apids/feedback/'
|
15
16
|
SCHEDULES_URL = BASE_URL + '/schedules/'
|
16
|
-
TAGS_URL = BASE_URL + '/tags/'
|
17
17
|
SEGMENTS_URL = BASE_URL + '/segments/'
|
18
|
+
NAMED_USER_URL = BASE_URL + '/named_users/'
|
19
|
+
REPORTS_URL = BASE_URL + '/reports/'
|
18
20
|
|
19
21
|
# Helper method for required keyword args in Ruby 2.0 that is compatible with 2.1+
|
20
22
|
# @example
|
@@ -92,14 +94,56 @@ module Urbanairship
|
|
92
94
|
# Parse Response Codes and trigger appropriate actions.
|
93
95
|
def self.check_code(response_code, response)
|
94
96
|
if response_code == 401
|
95
|
-
raise Unauthorized,
|
97
|
+
raise Unauthorized, 'Client is not authorized to make this request. The authorization credentials are incorrect or missing.'
|
96
98
|
elsif response_code == 403
|
97
|
-
raise Forbidden,
|
99
|
+
raise Forbidden, 'Client is forbidden from making this request. The application does not have the proper entitlement to access this feature.'
|
98
100
|
elsif !((200...300).include?(response_code))
|
99
101
|
raise AirshipFailure.new.from_response(response)
|
100
102
|
end
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
106
|
+
class PageIterator
|
107
|
+
include Urbanairship::Common
|
108
|
+
include Urbanairship::Loggable
|
109
|
+
include Enumerable
|
110
|
+
attr_accessor :data_attribute
|
111
|
+
|
112
|
+
def initialize(client: required('client'))
|
113
|
+
@client = client
|
114
|
+
@next_page = nil
|
115
|
+
@data_list = nil
|
116
|
+
@data_attribute = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def load_page
|
120
|
+
return false unless @next_page
|
121
|
+
response = @client.send_request(
|
122
|
+
method: 'GET',
|
123
|
+
url: @next_page
|
124
|
+
)
|
125
|
+
logger.info("Retrieving data from: #{@next_page}")
|
126
|
+
check_next_page = response['body']['next_page']
|
127
|
+
if check_next_page != @next_page
|
128
|
+
@next_page = check_next_page
|
129
|
+
elsif check_next_page
|
130
|
+
# if check_page = next_page, we have repeats in the response.
|
131
|
+
# and we don't want to load them
|
132
|
+
return false
|
133
|
+
else
|
134
|
+
@next_page = nil
|
135
|
+
end
|
136
|
+
@data_list = response['body'][@data_attribute]
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
140
|
+
def each
|
141
|
+
while load_page
|
142
|
+
@data_list.each do | value |
|
143
|
+
yield value
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
104
148
|
end
|
105
149
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'urbanairship'
|
2
|
+
|
3
|
+
|
4
|
+
module Urbanairship
|
5
|
+
module Devices
|
6
|
+
class ChannelTags
|
7
|
+
include Urbanairship::Common
|
8
|
+
include Urbanairship::Loggable
|
9
|
+
attr_writer :client
|
10
|
+
attr_reader :audience, :add_group, :remove_group, :set_group
|
11
|
+
|
12
|
+
def initialize(client: required('client'))
|
13
|
+
@client = client
|
14
|
+
@audience = {}
|
15
|
+
@add_group = {}
|
16
|
+
@remove_group = {}
|
17
|
+
@set_group = {}
|
18
|
+
@url = CHANNEL_URL + 'tags/'
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_audience(ios: nil, android: nil, amazon: nil)
|
22
|
+
if ios
|
23
|
+
@audience['ios_channel'] = ios
|
24
|
+
end
|
25
|
+
if android
|
26
|
+
@audience['android_channel'] = android
|
27
|
+
end
|
28
|
+
if amazon
|
29
|
+
@audience['amazon_channel'] = amazon
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add(group_name: required('group_name'), tags: required('tags'))
|
34
|
+
@add_group[group_name] = tags
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove(group_name: required('group_name'), tags: required('tags'))
|
38
|
+
@remove_group[group_name] = tags
|
39
|
+
end
|
40
|
+
|
41
|
+
def set(group_name: required('group_name'), tags: required('tags'))
|
42
|
+
@set_group[group_name] = tags
|
43
|
+
end
|
44
|
+
|
45
|
+
def send_request
|
46
|
+
payload = {}
|
47
|
+
|
48
|
+
fail ArgumentError,
|
49
|
+
'An audience is required for modifying tags' if @audience.empty?
|
50
|
+
fail ArgumentError,
|
51
|
+
'A tag request cannot both add and set tags' if !@add_group.empty? and !@set_group.empty?
|
52
|
+
fail ArgumentError,
|
53
|
+
'A tag request cannot both remove and set tags' if !@remove_group.empty? and !@set_group.empty?
|
54
|
+
fail ArgumentError,
|
55
|
+
'A tag request must add, remove, or set a tag' if @remove_group.empty? and @add_group.empty? and @set_group.empty?
|
56
|
+
|
57
|
+
payload['audience'] = @audience
|
58
|
+
payload['add'] = @add_group unless @add_group.empty?
|
59
|
+
payload['remove'] = @remove_group unless @remove_group.empty?
|
60
|
+
payload['set'] = @set_group unless @set_group.empty?
|
61
|
+
|
62
|
+
response = @client.send_request(
|
63
|
+
method: 'POST',
|
64
|
+
body: JSON.dump(payload),
|
65
|
+
url: @url,
|
66
|
+
content_type: 'application/json'
|
67
|
+
)
|
68
|
+
logger.info("Set tags for audience: #{@audience}")
|
69
|
+
response
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'urbanairship'
|
3
|
+
|
4
|
+
module Urbanairship
|
5
|
+
module Devices
|
6
|
+
class ChannelUninstall
|
7
|
+
include Urbanairship::Common
|
8
|
+
include Urbanairship::Loggable
|
9
|
+
attr_reader :client
|
10
|
+
|
11
|
+
# Initialize a ChannelUninstall Object
|
12
|
+
#
|
13
|
+
# @param [Object] client
|
14
|
+
def initialize(client: required('client'))
|
15
|
+
@client = client
|
16
|
+
end
|
17
|
+
|
18
|
+
def uninstall(channels: required('channels'))
|
19
|
+
chan_num = channels.length
|
20
|
+
fail ArgumentError,
|
21
|
+
'Maximum of 200 channel uninstalls exceeded.' if chan_num > 200
|
22
|
+
|
23
|
+
response = @client.send_request(
|
24
|
+
method: 'POST',
|
25
|
+
body: JSON.dump(channels),
|
26
|
+
url: CHANNEL_URL + 'uninstall/',
|
27
|
+
content_type: 'application/json'
|
28
|
+
)
|
29
|
+
|
30
|
+
logger.info { "Successfully uninstalled #{chan_num} channels." }
|
31
|
+
response
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'urbanairship'
|
2
|
+
|
3
|
+
|
4
|
+
module Urbanairship
|
5
|
+
module Devices
|
6
|
+
class ChannelInfo
|
7
|
+
include Urbanairship::Common
|
8
|
+
include Urbanairship::Loggable
|
9
|
+
attr_writer :client
|
10
|
+
|
11
|
+
def initialize(client: required('client'))
|
12
|
+
@client = client
|
13
|
+
end
|
14
|
+
|
15
|
+
def lookup(uuid: required('uuid'))
|
16
|
+
response = @client.send_request(
|
17
|
+
method: 'GET',
|
18
|
+
url: CHANNEL_URL + uuid
|
19
|
+
)
|
20
|
+
logger.info("Retrieved channel information for #{uuid}")
|
21
|
+
response['body']['channel']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class ChannelList < Urbanairship::Common::PageIterator
|
26
|
+
def initialize(client: required('client'))
|
27
|
+
super(client: client)
|
28
|
+
@next_page = CHANNEL_URL
|
29
|
+
@data_attribute = 'channels'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Feedback
|
34
|
+
include Urbanairship::Common
|
35
|
+
include Urbanairship::Loggable
|
36
|
+
|
37
|
+
def initialize(client: required('client'))
|
38
|
+
@client = client
|
39
|
+
end
|
40
|
+
|
41
|
+
def device_token(since: required('device token'))
|
42
|
+
url = DT_FEEDBACK_URL + '?since=' + since
|
43
|
+
get_feedback(url: url)
|
44
|
+
end
|
45
|
+
|
46
|
+
def apid(since: required('since'))
|
47
|
+
url = APID_FEEDBACK_URL + '?since=' + since
|
48
|
+
get_feedback(url: url)
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_feedback(url: required('url'))
|
52
|
+
response = @client.send_request(
|
53
|
+
method: 'GET',
|
54
|
+
url: url
|
55
|
+
)
|
56
|
+
logger.info("Requested feedback at url #{url}")
|
57
|
+
response
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'urbanairship'
|
2
|
+
|
3
|
+
|
4
|
+
module Urbanairship
|
5
|
+
module Devices
|
6
|
+
class NamedUser
|
7
|
+
include Urbanairship::Common
|
8
|
+
include Urbanairship::Loggable
|
9
|
+
attr_accessor :named_user_id
|
10
|
+
|
11
|
+
def initialize(client: required('client'))
|
12
|
+
@client = client
|
13
|
+
@named_user_id = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def associate(channel_id: required('channel_id'), device_type: required('device_type'))
|
17
|
+
fail ArgumentError,
|
18
|
+
'named_user_id is required for association' if @named_user_id.nil?
|
19
|
+
|
20
|
+
payload = {}
|
21
|
+
payload['channel_id'] = channel_id
|
22
|
+
payload['device_type'] = device_type
|
23
|
+
payload['named_user_id'] = @named_user_id
|
24
|
+
|
25
|
+
response = @client.send_request(
|
26
|
+
method: 'POST',
|
27
|
+
body: JSON.dump(payload),
|
28
|
+
url: NAMED_USER_URL + '/associate',
|
29
|
+
content_type: 'application/json'
|
30
|
+
)
|
31
|
+
logger.info { "Associated channel_id #{channel_id} with named_user #{@named_user_id}" }
|
32
|
+
response
|
33
|
+
end
|
34
|
+
|
35
|
+
def disassociate(channel_id: required('channel_id'), device_type: required('device_type'))
|
36
|
+
payload = {}
|
37
|
+
payload['channel_id'] = channel_id
|
38
|
+
payload['device_type'] = device_type
|
39
|
+
payload['named_user_id'] = @named_user_id unless @named_user_id.nil?
|
40
|
+
response = @client.send_request(
|
41
|
+
method: 'POST',
|
42
|
+
body: JSON.dump(payload),
|
43
|
+
url: NAMED_USER_URL + '/disassociate',
|
44
|
+
content_type: 'application/json'
|
45
|
+
)
|
46
|
+
logger.info { "Dissociated channel_id #{channel_id}" }
|
47
|
+
response
|
48
|
+
end
|
49
|
+
|
50
|
+
def lookup
|
51
|
+
fail ArgumentError,
|
52
|
+
'named_user_id is required for lookup' if @named_user_id.nil?
|
53
|
+
response = @client.send_request(
|
54
|
+
method: 'GET',
|
55
|
+
url: NAMED_USER_URL + '?id=' + @named_user_id,
|
56
|
+
)
|
57
|
+
logger.info { "Retrieved information on named_user_id #{@named_user_id}" }
|
58
|
+
response
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
class NamedUserTags < ChannelTags
|
64
|
+
include Urbanairship::Common
|
65
|
+
|
66
|
+
def initialize(client: required('client'))
|
67
|
+
super(client: client)
|
68
|
+
@url = NAMED_USER_URL + 'tags/'
|
69
|
+
end
|
70
|
+
|
71
|
+
def set_audience(user_ids: required('user_ids'))
|
72
|
+
@audience['named_user_id'] = user_ids
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
class NamedUserList < Urbanairship::Common::PageIterator
|
78
|
+
include Urbanairship::Common
|
79
|
+
|
80
|
+
def initialize(client: required('client'))
|
81
|
+
super(client: client)
|
82
|
+
@next_page = NAMED_USER_URL
|
83
|
+
@data_attribute = 'named_users'
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'urbanairship'
|
3
|
+
|
4
|
+
|
5
|
+
module Urbanairship
|
6
|
+
module Devices
|
7
|
+
class Segment
|
8
|
+
include Urbanairship::Common
|
9
|
+
include Urbanairship::Loggable
|
10
|
+
attr_accessor :display_name, :criteria
|
11
|
+
attr_reader :id
|
12
|
+
|
13
|
+
def initialize(client: required('client'))
|
14
|
+
@client = client
|
15
|
+
@display_name = nil
|
16
|
+
@criteria = nil
|
17
|
+
@id = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Build a Segment from the display_name and criteria attributes
|
21
|
+
#
|
22
|
+
# @param [Object] client The Client
|
23
|
+
# @return [Object] response HTTP response
|
24
|
+
def create
|
25
|
+
fail ArgumentError,
|
26
|
+
'Both display_name and criteria must be set to a value' if display_name.nil? or criteria.nil?
|
27
|
+
payload = {
|
28
|
+
:display_name => @display_name,
|
29
|
+
:criteria => @criteria
|
30
|
+
}
|
31
|
+
response = @client.send_request(
|
32
|
+
method: 'POST',
|
33
|
+
body: JSON.dump(payload),
|
34
|
+
url: SEGMENTS_URL,
|
35
|
+
content_type: 'application/json'
|
36
|
+
)
|
37
|
+
logger.info { "Successful segment creation: #{@display_name}" }
|
38
|
+
seg_url = response['headers'][:location]
|
39
|
+
@id = seg_url.split('/')[-1]
|
40
|
+
response
|
41
|
+
end
|
42
|
+
|
43
|
+
# Build a Segment from the display_name and criteria attributes
|
44
|
+
#
|
45
|
+
# @param [Object] id The id of the segment being looked up
|
46
|
+
def from_id(id: required('id'))
|
47
|
+
fail ArgumentError,
|
48
|
+
'id must be set to a valid string' if id.nil?
|
49
|
+
response = @client.send_request(
|
50
|
+
method: 'GET',
|
51
|
+
url: SEGMENTS_URL + id
|
52
|
+
)
|
53
|
+
logger.info("Retrieved segment information for #{id}")
|
54
|
+
@id = id
|
55
|
+
@criteria = response['body']['criteria']
|
56
|
+
@display_name = response['body']['display_name']
|
57
|
+
response
|
58
|
+
end
|
59
|
+
|
60
|
+
# Update a segment with new criteria/display_name
|
61
|
+
#
|
62
|
+
# @ returns [Object] response HTTP response
|
63
|
+
def update
|
64
|
+
fail ArgumentError,
|
65
|
+
'id cannot be nil' if @id.nil?
|
66
|
+
fail ArgumentError,
|
67
|
+
'Either display_name or criteria must be set to a value' if display_name.nil? and criteria.nil?
|
68
|
+
|
69
|
+
data = {}
|
70
|
+
data['display_name'] = @display_name
|
71
|
+
data['criteria'] = @criteria
|
72
|
+
response = @client.send_request(
|
73
|
+
method: 'PUT',
|
74
|
+
body: JSON.dump(data),
|
75
|
+
url: SEGMENTS_URL + @id,
|
76
|
+
content_type: 'application/json'
|
77
|
+
)
|
78
|
+
logger.info { "Successful segment update: #{@display_name}" }
|
79
|
+
response
|
80
|
+
end
|
81
|
+
|
82
|
+
# Delete a segment
|
83
|
+
#
|
84
|
+
# @ returns [Object] response HTTP response
|
85
|
+
def delete
|
86
|
+
fail ArgumentError,
|
87
|
+
'id cannot be nil' if @id.nil?
|
88
|
+
|
89
|
+
url = SEGMENTS_URL + @id
|
90
|
+
response = @client.send_request(
|
91
|
+
method: 'DELETE',
|
92
|
+
url: url
|
93
|
+
)
|
94
|
+
logger.info { "Successful segment deletion: #{@display_name}" }
|
95
|
+
response
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class SegmentList < Urbanairship::Common::PageIterator
|
100
|
+
include Urbanairship::Common
|
101
|
+
|
102
|
+
def initialize(client: required('client'))
|
103
|
+
super(client: client)
|
104
|
+
@next_page = SEGMENTS_URL
|
105
|
+
@data_attribute = 'segments'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|