tropo_rest 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +6 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +88 -0
  5. data/LICENSE +19 -0
  6. data/README.md +104 -0
  7. data/Rakefile +35 -0
  8. data/autotest/discover.rb +1 -0
  9. data/lib/faraday/request/serialize_json.rb +17 -0
  10. data/lib/faraday/response/raise_http_errors.rb +52 -0
  11. data/lib/faraday/response/resource.rb +26 -0
  12. data/lib/hashie/twash.rb +61 -0
  13. data/lib/tropo_rest/client/address.rb +76 -0
  14. data/lib/tropo_rest/client/application.rb +72 -0
  15. data/lib/tropo_rest/client/exchange.rb +18 -0
  16. data/lib/tropo_rest/client/session.rb +20 -0
  17. data/lib/tropo_rest/client/signal.rb +26 -0
  18. data/lib/tropo_rest/client.rb +27 -0
  19. data/lib/tropo_rest/configuration.rb +61 -0
  20. data/lib/tropo_rest/connection.rb +28 -0
  21. data/lib/tropo_rest/error.rb +33 -0
  22. data/lib/tropo_rest/request.rb +66 -0
  23. data/lib/tropo_rest/resource/address.rb +20 -0
  24. data/lib/tropo_rest/resource/application.rb +15 -0
  25. data/lib/tropo_rest/resource/exchange.rb +13 -0
  26. data/lib/tropo_rest/utils.rb +33 -0
  27. data/lib/tropo_rest/version.rb +3 -0
  28. data/lib/tropo_rest.rb +31 -0
  29. data/script/console +8 -0
  30. data/spec/spec_helper.rb +64 -0
  31. data/spec/tropo_rest/client/address_spec.rb +172 -0
  32. data/spec/tropo_rest/client/application_spec.rb +210 -0
  33. data/spec/tropo_rest/client/exchange_spec.rb +71 -0
  34. data/spec/tropo_rest/client/session_spec.rb +47 -0
  35. data/spec/tropo_rest/client/signal_spec.rb +34 -0
  36. data/spec/tropo_rest/client_spec.rb +246 -0
  37. data/spec/tropo_rest/resource/address_spec.rb +12 -0
  38. data/spec/tropo_rest/resource/application_spec.rb +12 -0
  39. data/spec/tropo_rest/resource/exchange_spec.rb +12 -0
  40. data/spec/tropo_rest_spec.rb +22 -0
  41. data/tropo_rest.gemspec +50 -0
  42. metadata +343 -0
@@ -0,0 +1,61 @@
1
+ require 'faraday'
2
+
3
+ module TropoRest
4
+ # Defines constants and methods related to configuration
5
+ module Configuration
6
+ VALID_OPTIONS_KEYS = [:username, :password, :adapter, :endpoint, :session_endpoint, :user_agent].freeze
7
+
8
+ # By default, don't set a username
9
+ DEFAULT_USERNAME = nil.freeze
10
+
11
+ # By default, don't set a password
12
+ DEFAULT_PASSWORD = nil.freeze
13
+
14
+ # The faraday adapter that will be used to connect if none is set
15
+ DEFAULT_ADAPTER = Faraday.default_adapter.freeze
16
+
17
+ # The endpoint that will be used to connect if none is set
18
+ #
19
+ # @note You shouldn't set this unless you don't want to use SSL.
20
+ DEFAULT_ENDPOINT = 'https://api.tropo.com/v1/'.freeze
21
+
22
+ # The endpoint that will be used for the creating sessions and sending signals
23
+ #
24
+ # @note You shouldn't set this unless you don't want to use SSL.
25
+ DEFAULT_SESSION_ENDPOINT = 'https://api.tropo.com/1.0/'.freeze
26
+
27
+ # The user agent that will be sent to the API endpoint if none is set
28
+ DEFAULT_USER_AGENT = "TropoRest Ruby Gem #{TropoRest::VERSION}".freeze
29
+
30
+ # @private
31
+ attr_accessor *VALID_OPTIONS_KEYS
32
+
33
+ # When this module is extended, set all configuration options to their default values
34
+ def self.extended(base)
35
+ base.reset
36
+ end
37
+
38
+ # Convenience method to allow configuration options to be set in a block
39
+ def configure
40
+ yield self
41
+ end
42
+
43
+ # Create a hash of options and their values
44
+ def options
45
+ VALID_OPTIONS_KEYS.inject({}) do |option, key|
46
+ option.merge!(key => send(key))
47
+ end
48
+ end
49
+
50
+ # Reset all configuration options to defaults
51
+ def reset
52
+ self.username = DEFAULT_USERNAME
53
+ self.password = DEFAULT_PASSWORD
54
+ self.adapter = DEFAULT_ADAPTER
55
+ self.endpoint = DEFAULT_ENDPOINT
56
+ self.session_endpoint = DEFAULT_SESSION_ENDPOINT
57
+ self.user_agent = DEFAULT_USER_AGENT
58
+ self
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,28 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'faraday/request/serialize_json'
4
+ require 'faraday/response/resource'
5
+ require 'faraday/response/raise_http_errors'
6
+
7
+ module TropoRest
8
+ module Connection
9
+ private
10
+
11
+ def connection(url, format, resource)
12
+ options = {
13
+ :headers => {'Accept' => "application/#{format}", 'User-Agent' => user_agent},
14
+ :url => url
15
+ }
16
+
17
+ Faraday::Connection.new(options) do |connection|
18
+ connection.use Faraday::Request::SerializeJson if format.to_sym == :json
19
+ connection.adapter(adapter)
20
+ connection.basic_auth(username, password)
21
+ connection.use Faraday::Response::ParseJson if format.to_sym == :json
22
+ connection.use Faraday::Response::ParseXml if format.to_sym == :xml
23
+ connection.use Faraday::Response::Resource, resource
24
+ connection.use Faraday::Response::RaiseHttpErrors
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,33 @@
1
+ module TropoRest
2
+ # Custom error class for rescuing from all TropoRest errors
3
+ #
4
+ # @see https://www.tropo.com/docs/rest/response_codes.htm
5
+ class Error < StandardError; end
6
+
7
+ # Raised when Tropo returns the HTTP status code 400
8
+ class BadRequest < Error; end
9
+
10
+ # Raised when Tropo returns the HTTP status code 401
11
+ class NotAuthorized < Error; end
12
+
13
+ # Raised when Tropo returns the HTTP status code 403
14
+ class AccessDenied < Error; end
15
+
16
+ # Raised when Tropo returns the HTTP status code 404
17
+ class NotFound < Error; end
18
+
19
+ # Raised when Tropo returns the HTTP status code 405
20
+ class MethodNotAllowed < Error; end
21
+
22
+ # Raised when Tropo returns the HTTP status code 415
23
+ class UnsupportedMediaType < Error; end
24
+
25
+ # Raised when Tropo returns the HTTP status code 500
26
+ class InternalServerError < Error; end
27
+
28
+ # Raised when Tropo returns the HTTP status code 503
29
+ class ServiceUnavailable < Error; end
30
+
31
+ # Raise when you pass invalid arguments to client methods
32
+ class ArgumentError < ArgumentError; end
33
+ end
@@ -0,0 +1,66 @@
1
+ module TropoRest
2
+ # Defines HTTP request methods
3
+ module Request
4
+ # Perform an HTTP GET request
5
+ def get(*args)
6
+ request(:get, *args)
7
+ end
8
+
9
+ # Perform an HTTP POST request
10
+ def post(*args)
11
+ request(:post, *args)
12
+ end
13
+
14
+ # Perform an HTTP PUT request
15
+ def put(*args)
16
+ request(:put, *args)
17
+ end
18
+
19
+ # Perform an HTTP DELETE request
20
+ def delete(*args)
21
+ request(:delete, *args)
22
+ end
23
+
24
+ private
25
+
26
+ def extract_request_args!(*args)
27
+ options = args.last.is_a?(Hash) ? args.pop : {}
28
+ path, resource = args
29
+ resource ||= Hashie::Mash
30
+ [path, resource, options]
31
+ end
32
+
33
+ # if a user passes in an HREF of a Tropo endpoint, return the path
34
+ # otherwise, mash the args into the supplied template
35
+ def get_path(template, *args)
36
+ first = args.first
37
+ if first =~ /^#{endpoint}#{template.gsub('%d', '\d+').gsub('%s', '.*')}$/
38
+ uri = URI.parse(first)
39
+ uri.path
40
+ else
41
+ template % args
42
+ end
43
+ end
44
+
45
+ # Perform an HTTP request
46
+ def request(method, *args)
47
+ path, resource, options = extract_request_args!(*args)
48
+
49
+ # Do we need the session endpoint?
50
+ url = path =~ /^\/?sessions/ ? session_endpoint : endpoint
51
+ # Need to parse XML for creating a session, but JSON for signals and everything else
52
+ format = path =~ /^\/?sessions$/ ? :xml : :json
53
+
54
+ response = connection(url, format, resource).send(method) do |request|
55
+ case method
56
+ when :get, :delete
57
+ request.url(path, options)
58
+ when :post, :put
59
+ request.path = path
60
+ request.body = options unless options.empty?
61
+ end
62
+ end
63
+ response.body
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,20 @@
1
+ module TropoRest
2
+ module Resource
3
+ class Address < Hashie::Twash
4
+
5
+ property :href
6
+ property :type
7
+ property :prefix
8
+ property :number
9
+ property :address
10
+ property :city
11
+ property :state
12
+ property :channel
13
+ property :username
14
+ property :password
15
+ property :token
16
+ property :application_id
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ module TropoRest
2
+ module Resource
3
+ class Application < Hashie::Twash
4
+
5
+ property :id
6
+ property :href
7
+ property :name
8
+ property :voice_url, :from => :voiceUrl
9
+ property :messaging_url, :from => :messagingUrl
10
+ property :platform
11
+ property :partition
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module TropoRest
2
+ module Resource
3
+ class Exchange < Hashie::Twash
4
+
5
+ property :prefix
6
+ property :city
7
+ property :state
8
+ property :country
9
+ property :description
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ module TropoRest
2
+ # Utilities
3
+ class Utils
4
+ # Convert hash keys from camel case to underscore
5
+ def self.underscore(hash)
6
+ dup = hash.dup
7
+ dup.keys.select { |k| k =~ /[A-Z]/ }.each do |k|
8
+ value = dup.delete(k)
9
+ key = k.dup
10
+ key.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
11
+ key.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
12
+ key.tr!("-", "_")
13
+ key.downcase!
14
+ dup[key] = value
15
+ end
16
+ dup
17
+ end
18
+
19
+ # Convert hash keys from underscore to camel case
20
+ def self.camelize(hash)
21
+ dup = hash.dup
22
+ dup.keys.each do |k|
23
+ value = dup.delete(k)
24
+ key = k.to_s.dup
25
+ if key =~ /_/
26
+ key = key[0].chr.downcase + key.gsub(/(?:^|_)(.)/) { $1.upcase }[1..-1]
27
+ end
28
+ dup[key] = value
29
+ end
30
+ dup
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module TropoRest
2
+ VERSION = "0.0.1"
3
+ end
data/lib/tropo_rest.rb ADDED
@@ -0,0 +1,31 @@
1
+ require 'hashie/twash'
2
+
3
+ require 'tropo_rest/resource/address'
4
+ require 'tropo_rest/resource/application'
5
+ require 'tropo_rest/resource/exchange'
6
+
7
+ require 'tropo_rest/version'
8
+ require 'tropo_rest/error'
9
+ require 'tropo_rest/configuration'
10
+ require 'tropo_rest/request'
11
+ require 'tropo_rest/connection'
12
+ require 'tropo_rest/client'
13
+ require 'tropo_rest/utils'
14
+
15
+ module TropoRest
16
+ extend Configuration
17
+
18
+ # Alias for TropoRest::Client.new
19
+ #
20
+ # @param options [Hash] Configuration options.
21
+ # @return [TropoRest::Client]
22
+ def self.client(options={})
23
+ TropoRest::Client.new(options)
24
+ end
25
+
26
+ # Delegate to TropoRest::Client
27
+ def self.method_missing(method, *args, &block)
28
+ return super unless client.respond_to?(method)
29
+ client.send(method, *args, &block)
30
+ end
31
+ end
data/script/console ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler'
3
+ Bundler.require
4
+
5
+ require "irb"
6
+ require 'tropo_rest'
7
+
8
+ IRB.start(__FILE__)
@@ -0,0 +1,64 @@
1
+ Bundler.require
2
+ require 'tropo_rest'
3
+ require 'webmock/rspec'
4
+
5
+ RSpec.configure do |config|
6
+ config.mock_with :rspec
7
+ config.include WebMock::API
8
+ end
9
+
10
+ def a_delete(path)
11
+ a_request(:delete, tropo_url_for(path))
12
+ end
13
+
14
+ def a_get(path)
15
+ a_request(:get, tropo_url_for(path))
16
+ end
17
+
18
+ def a_post(path)
19
+ a_request(:post, tropo_url_for(path))
20
+ end
21
+
22
+ def a_put(path)
23
+ a_request(:put, tropo_url_for(path))
24
+ end
25
+
26
+ def stub_delete(path)
27
+ stub_request(:delete, tropo_url_for(path))
28
+ end
29
+
30
+ def stub_get(path)
31
+ stub_request(:get, tropo_url_for(path))
32
+ end
33
+
34
+ def stub_post(path)
35
+ stub_request(:post, tropo_url_for(path))
36
+ end
37
+
38
+ def stub_put(path)
39
+ stub_request(:put, tropo_url_for(path))
40
+ end
41
+
42
+ def a_session_get(path)
43
+ a_request(:get, tropo_session_url_for(path))
44
+ end
45
+
46
+ def a_session_post(path)
47
+ a_request(:post, tropo_session_url_for(path))
48
+ end
49
+
50
+ def stub_session_get(path)
51
+ stub_request(:get, tropo_session_url_for(path))
52
+ end
53
+
54
+ def stub_session_post(path)
55
+ stub_request(:post, tropo_session_url_for(path))
56
+ end
57
+
58
+ def tropo_url_for(path)
59
+ TropoRest.endpoint + path
60
+ end
61
+
62
+ def tropo_session_url_for(path)
63
+ TropoRest.session_endpoint + path
64
+ end
@@ -0,0 +1,172 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe TropoRest::Client do
4
+
5
+ before do
6
+ @client = TropoRest::Client.new
7
+ end
8
+
9
+ describe "#addresses" do
10
+
11
+ before do
12
+ stub_get("applications/123456/addresses").to_return(:body => <<-JSON
13
+ [
14
+ {
15
+ "href": "https://api.tropo.com/v1/applications/123456/addresses/sip/99901123456@sip.tropo.com",
16
+ "type": "sip",
17
+ "address": "9990123456@sip.tropo.com"
18
+ },
19
+ {
20
+ "href": "https://api.tropo.com/v1/applications/123456/addresses/skype/+99000936209990123456",
21
+ "type": "skype",
22
+ "number": "+990009369990123456"
23
+ },
24
+ {
25
+ "href": "https://api.tropo.com/v1/applications/123456/addresses/number/+14075551234",
26
+ "type": "number",
27
+ "prefix": "1407",
28
+ "number": "4075551234",
29
+ "city": "Orlando",
30
+ "state": "FL"
31
+ },
32
+ {
33
+ "href": "https://api.tropo.com/v1/applications/123456/addresses/aim/tropocloud",
34
+ "type": "aim",
35
+ "username": "tropocloud"
36
+ }
37
+ ]
38
+ JSON
39
+ )
40
+ end
41
+
42
+ it "should make the request with an application ID" do
43
+ @client.addresses(123456)
44
+ a_get("applications/123456/addresses").should have_been_made
45
+ end
46
+
47
+ it "should make the request with an address HREF" do
48
+ @client.addresses("https://api.tropo.com/v1/applications/123456/addresses")
49
+ a_get("applications/123456/addresses").should have_been_made
50
+ end
51
+
52
+ it "should return a collection of addresses" do
53
+ @client.addresses(123456).should have(4).items
54
+ end
55
+
56
+ it "should return the correct addresses" do
57
+ apps = @client.addresses(123456)
58
+ first = apps[0]
59
+ second = apps[1]
60
+ third = apps[2]
61
+ fourth = apps[3]
62
+
63
+ first.should be_instance_of(TropoRest::Resource::Address)
64
+ first.href.should == "https://api.tropo.com/v1/applications/123456/addresses/sip/99901123456@sip.tropo.com"
65
+ first.type.should == "sip"
66
+ first.address.should == "9990123456@sip.tropo.com"
67
+
68
+ second.should be_instance_of(TropoRest::Resource::Address)
69
+ second.href.should == "https://api.tropo.com/v1/applications/123456/addresses/skype/+99000936209990123456"
70
+ second.type.should == "skype"
71
+ second.number.should == "+990009369990123456"
72
+
73
+ third.should be_instance_of(TropoRest::Resource::Address)
74
+ third.href.should == "https://api.tropo.com/v1/applications/123456/addresses/number/+14075551234"
75
+ third.type.should == "number"
76
+ third.prefix.should == "1407"
77
+ third.number.should == "4075551234"
78
+ third.city.should == "Orlando"
79
+ third.state.should == "FL"
80
+
81
+ fourth.should be_instance_of(TropoRest::Resource::Address)
82
+ fourth.href.should == "https://api.tropo.com/v1/applications/123456/addresses/aim/tropocloud"
83
+ fourth.type.should == "aim"
84
+ fourth.username.should == "tropocloud"
85
+ end
86
+
87
+ end
88
+
89
+ describe "#address" do
90
+
91
+ before do
92
+ stub_get("applications/123456/addresses/skype/+99000936209990123456").to_return(:body => <<-JSON
93
+ {
94
+ "href": "https://api.tropo.com/v1/applications/123456/addresses/skype/+99000936209990123456",
95
+ "type": "skype",
96
+ "number": "+990009369990123456"
97
+ }
98
+ JSON
99
+ )
100
+ end
101
+
102
+ it "should make the request with application ID, address type, and address identifier" do
103
+ @client.address(123456, "skype", "+99000936209990123456")
104
+ a_get("applications/123456/addresses/skype/+99000936209990123456").should have_been_made
105
+ end
106
+
107
+ it "should make the request with an address HREF" do
108
+ @client.address("https://api.tropo.com/v1/applications/123456/addresses/skype/+99000936209990123456")
109
+ a_get("applications/123456/addresses/skype/+99000936209990123456").should have_been_made
110
+ end
111
+
112
+ it "should return an address object" do
113
+ app = @client.address(123456, "skype", "+99000936209990123456")
114
+ app.should be_instance_of(TropoRest::Resource::Address)
115
+ app.href.should == "https://api.tropo.com/v1/applications/123456/addresses/skype/+99000936209990123456"
116
+ app.type.should == "skype"
117
+ app.number.should == "+990009369990123456"
118
+ end
119
+
120
+ end
121
+
122
+ describe "#create_address" do
123
+
124
+ before do
125
+ @params = {:type => "number", :prefix => "1407"}
126
+ stub_post("applications/123456/addresses").
127
+ with(:body => @params).
128
+ to_return(:body => %({"href":"https://api.tropo.com/v1/applications/123456/addresses/number/+14075551234"}))
129
+ end
130
+
131
+ it "should make the request with an application ID" do
132
+ @client.create_address(123456, @params)
133
+ a_post("applications/123456/addresses").with(:body => @params).should have_been_made
134
+ end
135
+
136
+ it "should make the request with an application HREF" do
137
+ @client.create_address("https://api.tropo.com/v1/applications/123456/addresses", @params)
138
+ a_post("applications/123456/addresses").with(:body => @params).should have_been_made
139
+ end
140
+
141
+ it "should return the href of the address" do
142
+ res = @client.create_address(123456, @params)
143
+ res.href.should == "https://api.tropo.com/v1/applications/123456/addresses/number/+14075551234"
144
+ end
145
+
146
+ end
147
+
148
+ describe "#delete_address" do
149
+
150
+ before do
151
+ stub_delete("applications/123456/addresses/skype/+99000936209990123456").
152
+ to_return(:body => %({"message": "delete successful"}))
153
+ end
154
+
155
+ it "should make the request with application ID, address type, and address identifier" do
156
+ @client.delete_address(123456, "skype", "+99000936209990123456")
157
+ a_delete("applications/123456/addresses/skype/+99000936209990123456").should have_been_made
158
+ end
159
+
160
+ it "should make the request with an address HREF" do
161
+ @client.delete_address("https://api.tropo.com/v1/applications/123456/addresses/skype/+99000936209990123456")
162
+ a_delete("applications/123456/addresses/skype/+99000936209990123456").should have_been_made
163
+ end
164
+
165
+ it "should return the message" do
166
+ res = @client.delete_address(123456, "skype", "+99000936209990123456")
167
+ res.message.should == "delete successful"
168
+ end
169
+
170
+ end
171
+
172
+ end