tropo_rest 0.0.1

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 (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