urbanairship 5.9.0 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,23 +4,67 @@ require 'urbanairship/loggable'
4
4
  module Urbanairship
5
5
  # Features mixed in to all classes
6
6
  module Common
7
- SERVER = 'go.urbanairship.com'
8
- BASE_URL = 'https://go.urbanairship.com/api'
9
- CHANNEL_URL = BASE_URL + '/channels/'
10
- OPEN_CHANNEL_URL = BASE_URL + '/channels/open/'
11
- DEVICE_TOKEN_URL = BASE_URL + '/device_tokens/'
12
- APID_URL = BASE_URL + '/apids/'
13
- PUSH_URL = BASE_URL + '/push/'
14
- SCHEDULES_URL = BASE_URL + '/schedules/'
15
- SEGMENTS_URL = BASE_URL + '/segments/'
16
- NAMED_USER_URL = BASE_URL + '/named_users/'
17
- REPORTS_URL = BASE_URL + '/reports/'
18
- LISTS_URL = BASE_URL + '/lists/'
19
- PIPELINES_URL = BASE_URL + '/pipelines/'
20
- FEEDS_URL = BASE_URL + '/feeds/'
21
- LOCATION_URL = BASE_URL + '/location/'
22
- CREATE_AND_SEND_URL = BASE_URL + '/create-and-send/'
23
- EXPERIMENTS_URL = BASE_URL + '/experiments/'
7
+ CONTENT_TYPE = 'application/json'
8
+
9
+ def apid_path(path='')
10
+ "/apids/#{path}"
11
+ end
12
+
13
+ def channel_path(path='')
14
+ "/channels/#{path}"
15
+ end
16
+
17
+ def create_and_send_path(path='')
18
+ "/create-and-send/#{path}"
19
+ end
20
+
21
+ def custom_events_path(path='')
22
+ "/custom-events/#{path}"
23
+ end
24
+
25
+ def device_token_path(path='')
26
+ "/device_tokens/#{path}"
27
+ end
28
+
29
+ def experiments_path(path='')
30
+ "/experiments/#{path}"
31
+ end
32
+
33
+ def lists_path(path='')
34
+ "/lists/#{path}"
35
+ end
36
+
37
+ def location_path(path='')
38
+ "/location/#{path}"
39
+ end
40
+
41
+ def named_users_path(path='')
42
+ "/named_users/#{path}"
43
+ end
44
+
45
+ def open_channel_path(path='')
46
+ "/open/#{path}"
47
+ end
48
+
49
+ def pipelines_path(path='')
50
+ "/pipelines/#{path}"
51
+ end
52
+
53
+ def push_path(path='')
54
+ "/push/#{path}"
55
+ end
56
+
57
+ def reports_path(path='')
58
+ "/reports/#{path}"
59
+ end
60
+
61
+ def schedules_path(path='')
62
+ "/schedules/#{path}"
63
+ end
64
+
65
+ def segments_path(path='')
66
+ "/segments/#{path}"
67
+ end
24
68
 
25
69
  # Helper method for required keyword args in Ruby 2.0 that is compatible with 2.1+
26
70
  # @example
@@ -115,36 +159,18 @@ module Urbanairship
115
159
 
116
160
  def initialize(client: required('client'))
117
161
  @client = client
118
- @next_page = nil
119
- @data_list = nil
120
- @data_attribute = nil
121
162
  @count = 0
122
- end
123
-
124
- def load_page
125
- return false unless @next_page
126
- response = @client.send_request(
127
- method: 'GET',
128
- url: @next_page
129
- )
130
- logger.info("Retrieving data from: #{@next_page}")
131
- check_next_page = response['body']['next_page']
132
- if check_next_page != @next_page
133
- @next_page = check_next_page
134
- elsif check_next_page
135
- # if check_page = next_page, we have repeats in the response.
136
- # and we don't want to load them
137
- return false
138
- else
139
- @next_page = nil
140
- end
141
- @data_list = response['body'][@data_attribute]
142
- true
163
+ @data_attribute = nil
164
+ @data_list = nil
165
+ @next_page_path = nil
166
+ @next_page_url = nil
143
167
  end
144
168
 
145
169
  def each
146
- while load_page
147
- @data_list.each do | value |
170
+ while @next_page_path || @next_page_url
171
+ load_page
172
+
173
+ @data_list.each do |value|
148
174
  @count += 1
149
175
  yield value
150
176
  end
@@ -154,6 +180,47 @@ module Urbanairship
154
180
  def count
155
181
  @count
156
182
  end
183
+
184
+ private
185
+
186
+ def load_page
187
+ logger.info("Retrieving data from: #{@next_page_url || @next_page_path}")
188
+ params = {
189
+ method: 'GET',
190
+ path: @next_page_path,
191
+ url: @next_page_url
192
+ }.select { |k, v| !v.nil? }
193
+ response = @client.send_request(params)
194
+
195
+ @data_list = get_new_data(response)
196
+ @next_page_url = get_next_page_url(response)
197
+ @next_page_path = nil
198
+ end
199
+
200
+ def extract_next_page_url(response)
201
+ response['body']['next_page']
202
+ end
203
+
204
+ def get_new_data(response)
205
+ potential_next_page_url = extract_next_page_url(response)
206
+
207
+ # if potential_next_page_url is the same as the current page, we have
208
+ # repeats in the response and we don't want to load them
209
+ return [] if potential_next_page_url && get_next_page_url(response).nil?
210
+
211
+ response['body'][@data_attribute]
212
+ end
213
+
214
+ def get_next_page_url(response)
215
+ potential_next_page_url = extract_next_page_url(response)
216
+ return nil if potential_next_page_url.nil?
217
+
218
+ # if potential_next_page_url is the same as the current page, we have
219
+ # repeats in the response and we don't want to check the next pages
220
+ return potential_next_page_url if @next_page_url && potential_next_page_url != @next_page_url
221
+ return potential_next_page_url if @next_page_path && !potential_next_page_url.end_with?(@next_page_path)
222
+ nil
223
+ end
157
224
  end
158
225
  end
159
226
  end
@@ -1,8 +1,9 @@
1
1
  module Urbanairship
2
2
  class Configuration
3
- attr_accessor :custom_logger, :log_path, :log_level, :timeout
3
+ attr_accessor :custom_logger, :log_path, :log_level, :server, :timeout
4
4
 
5
5
  def initialize
6
+ @server = 'go.urbanairship.com'
6
7
  @custom_logger = nil
7
8
  @log_path = nil
8
9
  @log_level = Logger::INFO
@@ -0,0 +1,60 @@
1
+ require 'uri'
2
+ require 'urbanairship'
3
+ require 'urbanairship/common'
4
+ require 'urbanairship/loggable'
5
+
6
+ module Urbanairship
7
+ module CustomEvents
8
+ class CustomEvent
9
+ include Urbanairship::Common
10
+ include Urbanairship::Loggable
11
+
12
+ attr_accessor :events
13
+
14
+ def initialize(client: required('client'))
15
+ @client = client
16
+ end
17
+
18
+ def create
19
+ fail ArgumentError, 'events must be an array of custom events' unless events.is_a?(Array)
20
+
21
+ response = @client.send_request(
22
+ auth_type: :bearer,
23
+ body: JSON.dump(events),
24
+ content_type: 'application/json',
25
+ method: 'POST',
26
+ path: custom_events_path
27
+ )
28
+ cer = CustomEventResponse.new(body: response['body'], code: response['code'])
29
+ logger.info { cer.format }
30
+
31
+ cer
32
+ end
33
+ end
34
+
35
+ # Response to a successful custom event creation.
36
+ class CustomEventResponse
37
+ attr_reader :ok, :operation_id, :payload, :status_code
38
+
39
+ def initialize(body: nil, code: nil)
40
+ @payload = (body.nil? || body.empty?) ? {} : body
41
+ @ok = payload['ok']
42
+ @operation_id = payload['operationId']
43
+ @status_code = code
44
+ end
45
+
46
+ # String Formatting of the CustomEventResponse
47
+ #
48
+ # @return [Object] String Formatted CustomEventResponse
49
+ def format
50
+ "Received [#{status_code}] response code.\nBody:\n#{formatted_body}"
51
+ end
52
+
53
+ def formatted_body
54
+ payload
55
+ .map { |key, value| "#{key}:\t#{value.to_s || 'None'}" }
56
+ .join("\n")
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,89 @@
1
+ require 'urbanairship'
2
+ require 'urbanairship/common'
3
+
4
+ module Urbanairship
5
+ module CustomEvents
6
+ module Payload
7
+ include Urbanairship::Common
8
+
9
+ def custom_events(
10
+ body: required('body'),
11
+ occurred: required('occurred'),
12
+ user: required('user')
13
+ )
14
+ compact_helper({
15
+ body: body,
16
+ occurred: format_timestamp(occurred),
17
+ user: user
18
+ })
19
+ end
20
+
21
+ # Body specific portion of CustomEvent Object
22
+ def custom_events_body(
23
+ interaction_id: nil, interaction_type: nil, name: required('name'),
24
+ properties: nil, session_id: nil, transaction: nil, value: nil
25
+ )
26
+
27
+ validates_name_format(name)
28
+ validates_value_format(value)
29
+
30
+ compact_helper({
31
+ interaction_id: interaction_id,
32
+ interaction_type: interaction_type,
33
+ name: name,
34
+ properties: properties,
35
+ session_id: session_id,
36
+ transaction: transaction,
37
+ value: value
38
+ })
39
+ end
40
+
41
+ # User specific portion of CustomEvent Object
42
+ def custom_events_user(
43
+ amazon_channel: nil, android_channel: nil, channel: nil,
44
+ ios_channel: nil, named_user_id: nil, web_channel: nil
45
+ )
46
+ res = compact_helper({
47
+ amazon_channel: amazon_channel,
48
+ android_channel: android_channel,
49
+ channel: channel,
50
+ ios_channel: ios_channel,
51
+ named_user_id: named_user_id,
52
+ web_channel: web_channel,
53
+ })
54
+
55
+ fail ArgumentError, 'at least one user identifier must be defined' if res.empty?
56
+
57
+ res
58
+ end
59
+
60
+
61
+ # Formatters
62
+ # ------------------------------------------------------------------------
63
+
64
+ def format_timestamp(timestamp)
65
+ return timestamp if timestamp.is_a?(String)
66
+
67
+ timestamp.strftime('%Y-%m-%dT%H:%M:%S')
68
+ end
69
+
70
+
71
+ # Validators
72
+ # ------------------------------------------------------------------------
73
+
74
+ NAME_REGEX = /^[a-z0-9_\-]+$/
75
+ def validates_name_format(name)
76
+ return if name =~ NAME_REGEX
77
+
78
+ fail ArgumentError, 'invalid "name": it must follows this pattern /^[a-z0-9_\-]+$/'
79
+ end
80
+
81
+ def validates_value_format(value)
82
+ return if value.nil?
83
+ return if value.is_a?(Numeric)
84
+
85
+ fail ArgumentError, 'invalid "value": must be a number'
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,53 @@
1
+
2
+ module Urbanairship
3
+ module Devices
4
+ class Attributes
5
+
6
+ SET = 'set'
7
+ REMOVE = 'remove'
8
+
9
+ def initialize(attributes)
10
+ @attributes = attributes
11
+ end
12
+
13
+ def payload
14
+ @payload ||= { attributes: attributes_list }
15
+ end
16
+
17
+ private
18
+
19
+ def attributes_list
20
+ @attributes.map{ |attribute| attribute_payload(attribute) }
21
+ end
22
+
23
+ def attribute_payload(attribute)
24
+ if REMOVE == attribute[:action]
25
+ remove_payload(attribute)
26
+ else
27
+ set_payload(attribute)
28
+ end
29
+ end
30
+
31
+ def set_payload(attribute)
32
+ {
33
+ action: SET,
34
+ key: attribute[:key],
35
+ value: attribute[:value],
36
+ timestamp: (attribute[:timestamp] || timestamp).iso8601,
37
+ }
38
+ end
39
+
40
+ def remove_payload(attribute)
41
+ {
42
+ action: REMOVE,
43
+ key: attribute[:key],
44
+ timestamp: (attribute[:timestamp] || timestamp).iso8601,
45
+ }
46
+ end
47
+
48
+ def timestamp
49
+ @timestamp ||= Time.now.utc
50
+ end
51
+ end
52
+ end
53
+ end
@@ -15,7 +15,7 @@ module Urbanairship
15
15
  @add_group = {}
16
16
  @remove_group = {}
17
17
  @set_group = {}
18
- @url = CHANNEL_URL + 'tags/'
18
+ @path = channel_path('tags/')
19
19
  end
20
20
 
21
21
  def set_audience(ios: nil, android: nil, amazon: nil)
@@ -62,7 +62,7 @@ module Urbanairship
62
62
  response = @client.send_request(
63
63
  method: 'POST',
64
64
  body: JSON.dump(payload),
65
- url: @url,
65
+ path: @path,
66
66
  content_type: 'application/json'
67
67
  )
68
68
  logger.info("Set tags for audience: #{@audience}")
@@ -23,7 +23,7 @@ module Urbanairship
23
23
  response = @client.send_request(
24
24
  method: 'POST',
25
25
  body: JSON.dump(channels),
26
- url: CHANNEL_URL + 'uninstall/',
26
+ path: channel_path('uninstall/'),
27
27
  content_type: 'application/json'
28
28
  )
29
29
 
@@ -31,32 +31,32 @@ module Urbanairship
31
31
  response
32
32
  end
33
33
  end
34
-
35
-
34
+
35
+
36
36
  class OpenChannelUninstall
37
37
  include Urbanairship::Common
38
38
  include Urbanairship::Loggable
39
39
  attr_reader :client
40
-
40
+
41
41
  def initialize(client: required('client'))
42
42
  @client = client
43
43
  end
44
-
44
+
45
45
  def uninstall(address: required('address'),
46
46
  open_platform: required('open_platform'))
47
-
47
+
48
48
  body = {
49
49
  address: address,
50
50
  open_platform_name: open_platform
51
51
  }
52
-
52
+
53
53
  response = @client.send_request(
54
54
  method: 'POST',
55
55
  body: JSON.dump(body),
56
- url: OPEN_CHANNEL_URL + 'uninstall/',
56
+ path: open_channel_path('uninstall/'),
57
57
  content_type: 'application/json'
58
58
  )
59
-
59
+
60
60
  logger.info { "Successfully uninstalled open channel with address: #{address}"}
61
61
  response
62
62
  end
@@ -44,7 +44,7 @@ module Urbanairship
44
44
  campaign_object = {'categories': campaigns}
45
45
  full_payload[:campaigns] = campaign_object
46
46
  end
47
-
47
+
48
48
  full_payload
49
49
  end
50
50
 
@@ -52,7 +52,7 @@ module Urbanairship
52
52
  response = @client.send_request(
53
53
  method: 'POST',
54
54
  body: JSON.dump(payload),
55
- url: CREATE_AND_SEND_URL,
55
+ path: create_and_send_path,
56
56
  content_type: 'application/json'
57
57
  )
58
58
  logger.info("Running create and send for addresses #{@addresses}")
@@ -63,7 +63,7 @@ module Urbanairship
63
63
  response = @client.send_request(
64
64
  method: 'POST',
65
65
  body: JSON.dump(payload),
66
- url: CREATE_AND_SEND_URL + 'validate',
66
+ path: create_and_send_path('validate'),
67
67
  content_type: 'application/json'
68
68
  )
69
69
  logger.info("Validating payload for create and send")
@@ -84,7 +84,7 @@ module Urbanairship
84
84
  response = @client.send_request(
85
85
  method: 'POST',
86
86
  body: JSON.dump(scheduled_payload),
87
- url: SCHEDULES_URL + 'create-and-send',
87
+ path: schedules_path('create-and-send'),
88
88
  content_type: 'application/json'
89
89
  )
90
90
  logger.info("Scheduling create and send operation with name #{@name}")
@@ -17,7 +17,7 @@ module Urbanairship
17
17
  def lookup(uuid: required('uuid'))
18
18
  response = @client.send_request(
19
19
  method: 'GET',
20
- url: CHANNEL_URL + uuid
20
+ path: channel_path(uuid)
21
21
  )
22
22
  logger.info("Retrieved channel information for #{uuid}")
23
23
  response['body']['channel']
@@ -36,7 +36,7 @@ module Urbanairship
36
36
  response = @client.send_request(
37
37
  method: 'POST',
38
38
  body: JSON.dump(payload),
39
- url: CHANNEL_URL + 'attributes',
39
+ path: channel_path('attributes'),
40
40
  content_type: 'application/json'
41
41
  )
42
42
  response
@@ -46,7 +46,7 @@ module Urbanairship
46
46
  class ChannelList < Urbanairship::Common::PageIterator
47
47
  def initialize(client: required('client'))
48
48
  super(client: client)
49
- @next_page = CHANNEL_URL
49
+ @next_page_path = channel_path
50
50
  @data_attribute = 'channels'
51
51
  end
52
52
  end
@@ -64,7 +64,7 @@ module Urbanairship
64
64
 
65
65
  resp = @client.send_request(
66
66
  method: 'GET',
67
- url: DEVICE_TOKEN_URL + token
67
+ path: device_token_path(token)
68
68
  )
69
69
  logger.info("Looking up info on device token #{token}")
70
70
  resp
@@ -77,7 +77,7 @@ module Urbanairship
77
77
 
78
78
  def initialize(client: required('client'))
79
79
  super(client: client)
80
- @next_page = DEVICE_TOKEN_URL
80
+ @next_page_path = device_token_path
81
81
  @data_attribute = 'device_tokens'
82
82
  end
83
83
  end
@@ -95,7 +95,7 @@ module Urbanairship
95
95
 
96
96
  resp = @client.send_request(
97
97
  method: 'GET',
98
- url: APID_URL + apid
98
+ path: apid_path(apid)
99
99
  )
100
100
  logger.info("Retrieved info on apid #{apid}")
101
101
  resp
@@ -105,9 +105,9 @@ module Urbanairship
105
105
  class APIDList < Urbanairship::Common::PageIterator
106
106
  def initialize(client: required('client'))
107
107
  super(client: client)
108
- @next_page = APID_URL
108
+ @next_page_path = apid_path
109
109
  @data_attribute = 'apids'
110
110
  end
111
111
  end
112
112
  end
113
- end
113
+ end
@@ -41,7 +41,7 @@ module Urbanairship
41
41
  response = @client.send_request(
42
42
  method: 'POST',
43
43
  body: JSON.dump(payload),
44
- url: CHANNEL_URL + 'email',
44
+ path: channel_path('email'),
45
45
  content_type: 'application/json'
46
46
  )
47
47
  logger.info("Registering email channel with address #{address}")
@@ -58,7 +58,7 @@ module Urbanairship
58
58
  response = @client.send_request(
59
59
  method: 'POST',
60
60
  body: JSON.dump(payload),
61
- url: CHANNEL_URL + 'email/uninstall',
61
+ path: channel_path('email/uninstall'),
62
62
  content_type: 'application/json'
63
63
  )
64
64
  logger.info("Uninstalling email channel with address #{address}")
@@ -70,7 +70,7 @@ module Urbanairship
70
70
 
71
71
  response = @client.send_request(
72
72
  method: 'GET',
73
- url: CHANNEL_URL + 'email/' + address
73
+ path: channel_path('email/' + address)
74
74
  )
75
75
  logger.info("Looking up email channel with address #{address}")
76
76
  response
@@ -95,7 +95,7 @@ module Urbanairship
95
95
 
96
96
  response = @client.send_request(
97
97
  method: 'PUT',
98
- url: CHANNEL_URL + 'email/' + channel_id,
98
+ path: channel_path('email/' + channel_id),
99
99
  body: JSON.dump(payload),
100
100
  content_type: 'application/json'
101
101
  )
@@ -109,7 +109,7 @@ module Urbanairship
109
109
 
110
110
  def initialize(client: required('client'))
111
111
  super(client: client)
112
- @url = CHANNEL_URL + 'email/tags'
112
+ @path = channel_path('email/tags')
113
113
  end
114
114
 
115
115
  def set_audience(email_address: required('email_address'))