nuntium_api 0.13 → 0.14

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.
Files changed (3) hide show
  1. data/lib/nuntium/exception.rb +10 -0
  2. data/lib/nuntium.rb +243 -58
  3. metadata +6 -5
@@ -0,0 +1,10 @@
1
+ class Nuntium
2
+ class Exception < ::StandardError
3
+ attr_accessor :properties
4
+
5
+ def initialize(msg, properties = {})
6
+ super msg
7
+ @properties = properties
8
+ end
9
+ end
10
+ end
data/lib/nuntium.rb CHANGED
@@ -6,150 +6,256 @@
6
6
  #
7
7
  # === Example
8
8
  #
9
- # api = Nuntium.new 'service_url', 'account_name', 'application_name', 'application_password'
9
+ # require 'rubygems'
10
+ # require 'nuntium'
11
+ #
12
+ # api = Nuntium.new "service_url", "account_name", "application_name", "application_password"
13
+ #
14
+ # # Get all countries
15
+ # countries = api.countries
16
+ #
17
+ # # Get all carriers that belong to a specific country
18
+ # carriers = api.carriers 'ar'
19
+ #
20
+ # # Get all channels
21
+ # channels = api.channels
22
+ #
23
+ # # Create a channel
24
+ # api.create_channel {
25
+ # :name => "my_channel",
26
+ # :kind => "clickatell",
27
+ # :protocol => "sms",
28
+ # :direction =>"bidirectional",
29
+ # :enabled => true,
30
+ # :priority => 10,
31
+ # :configuration => {:password => "secret"}
32
+ # }
33
+ #
34
+ # message = {
35
+ # :from => "sms://1234",
36
+ # :to => "sms://5678",
37
+ # :subject => "Hi",
38
+ # :body => "Hello Nuntium!",
39
+ # }
40
+ #
41
+ # # Send an Application Originated message.
42
+ # # The response is of type HTTParty::Response
43
+ # response = api.send_ao message
44
+ #
45
+ # # Can also send many messages at once
46
+ # messages = [{:to => "sms://1", :body => 'One'}, {:to => "sms://2", :body => 'Two'}]
47
+ # response = api.send_ao messages
48
+ #
49
+ # # Simulate sending and get a list of candidate channels
50
+ # api.get_candidate_channels_for_ao message
51
+
10
52
  require 'rubygems'
11
- require 'httparty'
53
+ require 'net/http'
12
54
  require 'json'
55
+ require 'rest_client'
56
+ require 'cgi'
57
+ require File.expand_path('../nuntium/exception', __FILE__)
13
58
 
14
59
  # Provides access to the Nuntium Public API.
15
60
  class Nuntium
16
- include HTTParty
17
-
18
61
  # Creates an application-authenticated Nuntium api access.
19
62
  def initialize(url, account, application, password)
20
63
  @url = url
21
64
  @account = account
22
65
  @application = application
23
- @auth = {:username => "#{account}/#{application}", :password => password}
66
+ @options = {
67
+ :user => "#{account}/#{application}",
68
+ :password => password,
69
+ :headers => {:content_type => 'application/json'},
70
+ }
24
71
  end
25
72
 
26
- # Gets the list of countries known to Nuntium.
73
+ # Gets the list of countries known to Nuntium as an array of hashes.
74
+ #
75
+ # Raises Nuntium::Exception if something goes wrong.
27
76
  def countries
28
- self.class.get "#{@url}/api/countries.json"
77
+ get_json "/api/countries.json"
29
78
  end
30
79
 
31
- # Gets a country given its iso2 or iso3 code, or nil if a country with that iso does not exist.
80
+ # Gets a country as a hash given its iso2 or iso3 code, or nil if a country with that iso does not exist.
81
+ #
82
+ # Raises Nuntium::Exception if something goes wrong.
32
83
  def country(iso)
33
- c = self.class.get "#{@url}/api/countries/#{iso}.json"
34
- return nil if c.class <= String
35
- c
84
+ get_json "/api/countries/#{iso}.json"
36
85
  end
37
86
 
38
- # Gets the list of carriers known to Nuntium that belong to a country, given its
39
- # iso2 or iso3 code. Gets all carriers if no country is specified.
87
+ # Gets the list of carriers known to Nuntium that belong to a country as an array of hashes, given its
88
+ # iso2 or iso3 code. Gets all carriers as an array of hashes if no country is specified.
89
+ #
90
+ # Raises Nuntium::Exception if something goes wrong.
40
91
  def carriers(country_id = nil)
41
92
  if country_id
42
- self.class.get "#{@url}/api/carriers.json", :query => {:country_id => country_id}
93
+ get_json "/api/carriers.json?country_id=#{country_id}"
43
94
  else
44
- self.class.get "#{@url}/api/carriers.json"
95
+ get_json "/api/carriers.json"
45
96
  end
46
97
  end
47
98
 
48
- # Gets a carrier given its guid, or nil if a carrier with that guid does not exist.
99
+ # Gets a carrier as a hash given its guid, or nil if a carrier with that guid does not exist.
100
+ #
101
+ # Raises Nuntium::Exception if something goes wrong.
49
102
  def carrier(guid)
50
- c = self.class.get "#{@url}/api/carriers/#{guid}.json"
51
- return nil if c.class <= String
52
- c
103
+ get_json "/api/carriers/#{guid}.json"
53
104
  end
54
105
 
55
106
  # Returns the list of channels belonging to the application or that don't
56
- # belong to any application.
107
+ # belong to any application, as an array of hashes.
108
+ #
109
+ # Raises Nuntium::Exception if something goes wrong.
57
110
  def channels
58
- chans = self.class.get "#{@url}/api/channels.json", :basic_auth => @auth
59
- return nil if chans.class <= String
60
- chans.each do |channel|
61
- read_configuration channel
111
+ get "/api/channels.json" do |response, error|
112
+ raise Nuntium::Exception.new error.message if error
113
+
114
+ channels = JSON.parse response.body
115
+ channels.each { |channel| read_configuration channel }
116
+ channels
62
117
  end
63
118
  end
64
119
 
65
- # Returns a chnanel given its name, or nil if the channel doesn't exist
120
+ # Returns a channel given its name. Raises when the channel does not exist.
121
+ #
122
+ # Raises Nuntium::Exception if something goes wrong.
66
123
  def channel(name)
67
- response = self.class.get "#{@url}/api/channels/#{name}.json", :basic_auth => @auth
68
- return_channel response
124
+ get_channels "/api/channels/#{name}.json"
69
125
  end
70
126
 
71
127
  # Creates a channel.
128
+ #
72
129
  # create_channel :name => 'foo', :kind => 'qst_server', :protocol => 'sms', :configuration => {:password => 'bar'}
130
+ #
131
+ # Raises Nuntium::Exception if something goes wrong. You can access specific errors on properties via the properties
132
+ # accessor of the exception.
73
133
  def create_channel(channel)
74
134
  write_configuration channel
75
- response = self.class.post "#{@url}/api/channels.json", :basic_auth => @auth, :body => channel.to_json
76
- return_channel response
135
+ post "/api/channels.json", channel.to_json do |response, error|
136
+ handle_channel_error error if error
137
+
138
+ channel = JSON.parse response
139
+ read_configuration channel
140
+ channel
141
+ end
77
142
  end
78
143
 
79
144
  # Updates a channel.
145
+ #
80
146
  # update_channel :name => 'foo', :kind => 'qst_server', :protocol => 'sms', :configuration => {:password => 'bar'}
147
+ #
148
+ # Raises Nuntium::Exception if something goes wrong. You can access specific errors on properties via the properties
149
+ # accessor of the exception.
81
150
  def update_channel(channel)
82
151
  write_configuration channel
83
- response = self.class.put "#{@url}/api/channels/#{channel['name'] || channel[:name]}.json", :basic_auth => @auth, :body => channel.to_json
84
- return_channel response
152
+ channel_name = channel['name'] || channel[:name]
153
+
154
+ put "/api/channels/#{channel_name}.json", channel.to_json do |response, error|
155
+ handle_channel_error error if error
156
+
157
+ channel = JSON.parse response.body
158
+ read_configuration channel
159
+ channel
160
+ end
85
161
  end
86
162
 
87
163
  # Deletes a chnanel given its name.
164
+ #
165
+ # Raises Nuntium::Exception if something goes wrong.
88
166
  def delete_channel(name)
89
- self.class.delete "#{@url}/api/channels/#{name}", :basic_auth => @auth
167
+ delete "/api/channels/#{name}" do |response, error|
168
+ raise Nuntium::Exception.new error.message if error
169
+
170
+ response
171
+ end
90
172
  end
91
173
 
92
- # Returns the list of candidate channels when simulating routing the given
93
- # AO message.
174
+ # Returns the list of candidate channels when simulating routing the given AO message.
175
+ #
94
176
  # candidate_channels_for_ao :from => 'sms://1', :to => 'sms://2', :subject => 'hello', :body => 'hi!'
177
+ #
178
+ # Raises Nuntium::Exception if something goes wrong.
95
179
  def candidate_channels_for_ao(message)
96
- chans = self.class.get "#{@url}/api/candidate/channels.json", :basic_auth => @auth, :body => message
97
- return nil if chans.class <= String
98
- chans.each do |channel|
99
- read_configuration channel
100
- end
180
+ get_channels "/api/candidate/channels.json?#{to_query message}"
101
181
  end
102
182
 
103
183
  # Sends one or many AO messages.
104
184
  # Returns an enhanced HTTParty::Response instance with id, guid and token readers that matches those x-headers
105
185
  # returned by Nuntium.
186
+ #
106
187
  # To send a token, just include it in the message as :token => 'my_token'
188
+ #
107
189
  # send_ao :from => 'sms://1', :to => 'sms://2', :subject => 'hello', :body => 'hi!'
108
190
  # send_ao [{:from => 'sms://1', :to => 'sms://2', :subject => 'hello', :body => 'hi!'}, {...}]
191
+ #
192
+ # Returns a hash with :id, :guid and :token keys if a single message was sent, otherwise
193
+ # returns a hash with a :token key.
194
+ #
195
+ # Raises Nuntium::Exception if something goes wrong.
109
196
  def send_ao(messages)
110
- response = if messages.is_a? Array
111
- self.class.post "#{@url}/#{@account}/#{@application}/send_ao.json", :basic_auth => @auth, :body => messages.to_json
197
+ if messages.is_a? Array
198
+ post "/#{@account}/#{@application}/send_ao.json", messages.to_json do |response, error|
199
+ raise Nuntium::Exception.new error.message if error
200
+
201
+ {:token => response.headers[:x_nuntium_token]}
202
+ end
112
203
  else
113
- self.class.post "#{@url}/#{@account}/#{@application}/send_ao", :basic_auth => @auth, :body => messages
204
+ get "/#{@account}/#{@application}/send_ao?#{to_query messages}" do |response, error|
205
+ raise Nuntium::Exception.new error.message if error
206
+
207
+ {
208
+ :id => response.headers[:x_nuntium_id],
209
+ :guid => response.headers[:x_nuntium_guid],
210
+ :token => response.headers[:x_nuntium_token],
211
+ }
212
+ end
114
213
  end
115
- def response.id; headers['x-nuntium-id']; end
116
- def response.token; headers['x-nuntium-token']; end
117
- def response.guid; headers['x-nuntium-guid']; end
118
- response
119
214
  end
120
215
 
121
216
  # Gets AO messages that have the given token. The response is an array of hashes with the messages' attributes.
217
+ #
218
+ # Raises Nuntium::Exception if something goes wrong.
122
219
  def get_ao(token)
123
- self.class.get "#{@url}/#{@account}/#{@application}/get_ao.json?token=#{token}", :basic_auth => @auth
220
+ get_json "/#{@account}/#{@application}/get_ao.json?token=#{token}"
124
221
  end
125
222
 
126
223
  # Gets the custom attributes specified for a given address. Returns a hash with the attributes
224
+ #
225
+ # Raises Nuntium::Exception if something goes wrong.
127
226
  def get_custom_attributes(address)
128
- attrs = self.class.get "#{@url}/api/custom_attributes?address=#{address}", :basic_auth => @auth
129
- return nil unless attrs.is_a? Hash
130
- attrs
227
+ get_json "/api/custom_attributes?address=#{address}"
131
228
  end
132
229
 
230
+ # Sets custom attributes of a given address.
231
+ #
232
+ # Raises Nuntium::Exception if something goes wrong.
133
233
  def set_custom_attributes(address, attributes)
134
- self.class.post "#{@url}/api/custom_attributes?address=#{address}", :basic_auth => @auth, :body => attributes
234
+ post "/api/custom_attributes?address=#{address}", attributes.to_json do |response, error|
235
+ raise Nuntium::Exception.new error.message if error
236
+
237
+ nil
238
+ end
135
239
  end
136
240
 
137
241
  private
138
242
 
139
243
  def write_configuration(channel)
244
+ return unless channel[:configuration] || channel['configuration']
245
+
140
246
  configuration = []
141
- channel[:configuration].each do |name, value|
247
+ (channel[:configuration] || channel['configuration']).each do |name, value|
142
248
  configuration << {:name => name, :value => value}
143
249
  end
144
- channel[:configuration] = configuration
250
+ if channel[:configuration]
251
+ channel[:configuration] = configuration
252
+ else
253
+ channel['configuration'] = configuration
254
+ end
145
255
  end
146
256
 
147
257
  def read_configuration(channel)
148
- configuration = {}
149
- (channel['configuration'] || channel[:configuration]).each do |hash|
150
- configuration[hash['name'] || hash[:name]] = hash['value'] || hash[:value]
151
- end
152
- channel['configuration'] = configuration
258
+ channel['configuration'] = Hash[channel['configuration'].map { |e| [e['name'], e['value']] }]
153
259
  end
154
260
 
155
261
  def return_channel(response)
@@ -164,4 +270,83 @@ class Nuntium
164
270
  end
165
271
  end
166
272
 
273
+ def get(path)
274
+ resource = RestClient::Resource.new @url, @options
275
+ resource = resource[path].get
276
+ yield resource, nil
277
+ rescue RestClient::Exception => ex
278
+ yield nil, ex
279
+ rescue Errno::ECONNREFUSED => ex
280
+ yield nil, ex
281
+ end
282
+
283
+ def get_json(path)
284
+ get(path) do |response, error|
285
+ raise Nuntium::Exception.new error.message if error
286
+
287
+ JSON.parse response.body
288
+ end
289
+ end
290
+
291
+ def get_channels(path)
292
+ get(path) do |response, error|
293
+ raise Nuntium::Exception.new error.message if error
294
+
295
+ channels = JSON.parse response.body
296
+ channels.each { |channel| read_configuration channel }
297
+ channels
298
+ end
299
+ end
300
+
301
+ def post(path, data)
302
+ resource = RestClient::Resource.new @url, @options
303
+ resource = resource[path].post(data)
304
+ yield resource, nil
305
+ rescue RestClient::Exception => ex
306
+ yield nil, ex
307
+ rescue Errno::ECONNREFUSED => ex
308
+ yield nil, ex
309
+ end
310
+
311
+ def put(path, data)
312
+ resource = RestClient::Resource.new @url, @options
313
+ resource = resource[path].put(data)
314
+ yield resource, nil
315
+ rescue RestClient::Exception => ex
316
+ yield nil, ex
317
+ rescue Errno::ECONNREFUSED => ex
318
+ yield nil, ex
319
+ end
320
+
321
+ def delete(path, data)
322
+ resource = RestClient::Resource.new @url, @options
323
+ resource = resource[path].delete
324
+ yield resource, nil
325
+ rescue RestClient::Exception => ex
326
+ yield nil, ex
327
+ rescue Errno::ECONNREFUSED => ex
328
+ yield nil, ex
329
+ end
330
+
331
+ def handle_channel_error(error)
332
+ if error.is_a? RestClient::BadRequest
333
+ response = JSON.parse error.response.body
334
+ raise Nuntium::Exception.new response['summary'], Hash[response['properties'].map {|e| [e.keys[0], e.values[0]]}]
335
+ else
336
+ raise Nuntium::Exception.new error.message
337
+ end
338
+ end
339
+
340
+ def to_query(hash)
341
+ query = ''
342
+ first = true
343
+ hash.each do |key, value|
344
+ query << '&' unless first
345
+ query << key.to_s
346
+ query << '='
347
+ query << CGI.escape(value.to_s)
348
+ first = false
349
+ end
350
+ query
351
+ end
167
352
  end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nuntium_api
3
3
  version: !ruby/object:Gem::Version
4
- hash: 17
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 13
9
- version: "0.13"
8
+ - 14
9
+ version: "0.14"
10
10
  platform: ruby
11
11
  authors:
12
12
  - InsTEDD
@@ -14,10 +14,10 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-09-02 00:00:00 Z
17
+ date: 2011-09-22 00:00:00 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
- name: httparty
20
+ name: rest-client
21
21
  prerelease: false
22
22
  requirement: &id001 !ruby/object:Gem::Requirement
23
23
  none: false
@@ -55,6 +55,7 @@ extra_rdoc_files: []
55
55
  files:
56
56
  - lib/nuntium_api.rb
57
57
  - lib/nuntium.rb
58
+ - lib/nuntium/exception.rb
58
59
  homepage: http://code.google.com/p/nuntium-api-ruby
59
60
  licenses: []
60
61