Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial project commit

  • Loading branch information...
commit ae3ed3a683608e21c4565dd1ea3ecd1f55ab5ebd 0 parents
@jsgoecke jsgoecke authored
24 .gitignore
@@ -0,0 +1,24 @@
+## MAC OS
+.DS_Store
+.document
+.yardoc
+
+## TEXTMATE
+*.tmproj
+tmtags
+
+## EMACS
+*~
+\#*
+.\#*
+
+## VIM
+*.swp
+
+## PROJECT::GENERAL
+coverage
+rdoc
+pkg
+doc
+
+## PROJECT::SPECIFIC
1  .rspec
@@ -0,0 +1 @@
+--color
21 LICENSE
@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2010 Voxeo, Corporation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
85 README.rdoc
@@ -0,0 +1,85 @@
+= Tropo Provisioning API Ruby Library
+
+A Ruby library for interaction with the Tropo Provisioning API (http://tropo.com) using JSON.
+
+== Tropo Provisioning API Overview
+
+The Provisioning API provides a programmatic method to access the Tropo Provisioning Database, which is the centralized server that contains all of your applications, phone numbers, IM network information, tokens and so on. Previously, in order to create/delete applications, add/remove addresses (phone and SMS numbers, IM Accounts and tokens), or view available exchanges (area codes and their associated regions) you would need to log into the Tropo website and make your changes through your web browser. That poses a problem for an external program that needs access to your account and applications.
+
+As an example, say you're a phone system provider - someone who creates and hosts an IVR system for doctor's offices, school systems and so on. If you wanted to provide your customers with a method to purchase additional phone numbers via a website or similar portal, you would need to provide your purchasing system with access to our Provisioning Server to create and publish the new phone number. Without the Provisioning API, you would have to manually log into the Tropo website, add the phone number to the application, then provide the customer with the new number directly. With the Provisioning API, you're able to send the request directly to the Provisioning Server through your portal, create the phone number, publish it and provide it back to your customer without any manual interaction whatsoever.
+
+== How it works
+
+The Provisioning API is a RESTful Web Service that utilizes HTTP and JSON to allow for communication back and forth between an application and the Provisioning Server.
+
+== Gem Overview
+
+The Tropo Provisioning gem provides a library for convenient access to the Tropo Provisioning API.
+
+== Requirements
+
+* Unit tests passed on: Ruby MRI v1.8.6/1.8.7, Ruby 1.9.2, JRuby 1.5.0 and MacRuby 0.6
+* RubyGems
+
+== Installation
+
+ $ sudo gem install tropo-provisioning
+
+== Usage
+
+ require 'rubygems'
+ require 'tropo-provisioning'
+
+ tp = TropoProvisioning.new('username', 'password')
+
+=== Examples
+
+==== Add a New Application
+
+ app_id = tp.add_application({ :name => 'My Shiny New App',
+ :voiceUrl => 'http://mydomain.com/voice_script.rb',
+ :partition => 'staging',
+ :messagingUrl => 'http://mydomain.com/message_script.rb',
+ :platform => 'scripting' })
+
+==== Add a Address to an Application
+
+ address_data = tp.add_address(app_id, { :type => 'did', :prefix => '1415' })
+
+==== Delete a Address to an Application
+
+ result = tp.delete_address(app_id, address_data['number'])
+
+==== Delete an Application
+
+ tp.delete_application(app_id)
+
+== Documentation
+
+==== API Documentation:
+
+ http://voxeo.github.com/tropo-webapi-ruby
+
+==== Tropo Provisioning API Documentation
+
+ TBD
+
+=== Local & Generating Documentation
+
+==== Developer
+
+ $ gemserver
+
+==== Project Developer
+
+Install the Yard Doc (http://yardoc.org) gem:
+
+ $ sudo gem install yardoc
+
+From within the project:
+
+ $ yardoc
+
+== Copyright
+
+Copyright (c) 2010 Voxeo, Corporation. See LICENSE for details.
46 Rakefile
@@ -0,0 +1,46 @@
+require 'rubygems'
+require 'rake'
+
+begin
+ require 'jeweler'
+ Jeweler::Tasks.new do |gem|
+ gem.name = "tropo-provisioning"
+ gem.summary = "Library for interacting with the Tropo Provisioning API"
+ gem.description = "Library for interacting with the Tropo Provisioning API"
+ gem.email = "jsgoecke@voxeo.com"
+ gem.homepage = "http://github.com/voxeo/tropo-provisioning"
+ gem.authors = ["Jason Goecke"]
+ gem.add_development_dependency "rspec", ">= 1.2.9"
+ gem.add_dependency "hashie", ">= 0.2.1"
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
+ end
+ Jeweler::GemcutterTasks.new
+rescue LoadError
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
+end
+
+require 'spec/rake/spectask'
+Spec::Rake::SpecTask.new(:spec) do |spec|
+ spec.libs << 'lib' << 'spec'
+ spec.spec_files = FileList['spec/**/*_spec.rb']
+end
+
+Spec::Rake::SpecTask.new(:rcov) do |spec|
+ spec.libs << 'lib' << 'spec'
+ spec.pattern = 'spec/**/*_spec.rb'
+ spec.rcov = true
+end
+
+task :spec => :check_dependencies
+
+task :default => :spec
+
+require 'rake/rdoctask'
+Rake::RDocTask.new do |rdoc|
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
+
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = "tropo-provisioning #{version}"
+ rdoc.rdoc_files.include('README*')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
1  VERSION
@@ -0,0 +1 @@
+0.0.1
18 examples/add_addresses.rb
@@ -0,0 +1,18 @@
+require 'rubygems'
+require 'yaml'
+require 'lib/tropo-provisioning'
+
+config = YAML.load(File.open('examples/config.yml'))
+app_details = YAML.load(File.open("examples/#{config['filename']}"))
+
+# Create a new provisioning object with your Tropo credentials
+provisioning = TropoProvisioning.new(config['tropo']['username'], config['tropo']['password'])
+
+# Add a address by prefix
+p provisioning.add_address(app_details.application_id, { :type => 'number', :prefix => provisioning.exchanges[0]['prefix'] })
+
+# Add a address with a specific numbers
+# p provisioning.add_address(app_details.application_id, { :type => 'number', :number => '13035551212' })
+
+# Add an instant messaging address
+p provisioning.add_address(app_details.application_id, { :type => 'jabber', :username => 'xyz123@bot.im' })
3  examples/app_details.yml
@@ -0,0 +1,3 @@
+--- !map:Hashie::Mash
+href: http://api.tropo.com/provisioning/applications/121906
+application_id: "121906"
5 examples/config.yml
@@ -0,0 +1,5 @@
+tropo:
+ username: jsgoecke
+ password: test123
+
+filename: app_details.yml
21 examples/create_application.rb
@@ -0,0 +1,21 @@
+require 'rubygems'
+require 'yaml'
+require 'lib/tropo-provisioning'
+
+config = YAML.load(File.open('examples/config.yml'))
+
+# Create a new provisioning object with your Tropo credentials
+provisioning = TropoProvisioning.new(config['tropo']['username'], config['tropo']['password'])
+
+# Then create the application you would like to
+result = provisioning.create_application({ :name => 'Provisioning Test',
+ :voiceUrl => 'http://mydomain.com/voice_script.rb',
+ :partition => 'staging',
+ :messagingUrl => 'http://mydomain.com/message_script.rb',
+ :platform => 'scripting' })
+
+File.open("examples/#{config['filename']}", 'w') do |f|
+ f.write(result.to_yaml)
+end
+
+p result
11 examples/delete_application.rb
@@ -0,0 +1,11 @@
+require 'rubygems'
+require 'lib/tropo-provisioning'
+
+config = YAML.load(File.open('examples/config.yml'))
+app_details = YAML.load(File.open("examples/#{config['filename']}"))
+
+# Create a new provisioning object with your Tropo credentials
+provisioning = TropoProvisioning.new(config['tropo']['username'], config['tropo']['password'])
+
+# Then create the application you would like to
+p provisioning.delete_application(app_details.application_id)
25 examples/delete_applications.rb
@@ -0,0 +1,25 @@
+## WARNING ##
+# IF YOU RUN THIS SCRIPT, IT WILL DELETE ALL OF YOUR APPLICATIONS #
+## WARNING ##
+
+require 'rubygems'
+require 'lib/tropo-provisioning'
+
+config = YAML.load(File.open('examples/config.yml'))
+
+# Create a new provisioning object with your Tropo credentials
+provisioning = TropoProvisioning.new(config['tropo']['username'],
+ config['tropo']['password'],
+ :base_uri => 'http://api.tropo.com/provisioning')
+
+applications = provisioning.applications
+
+p applications
+
+applications.each do |app|
+ provisioning.delete_application(app.application_id)
+end
+
+## WARNING ##
+# IF YOU RUN THIS SCRIPT, IT WILL DELETE ALL OF YOUR APPLICATIONS #
+## WARNING ##
18 examples/list_addresses.rb
@@ -0,0 +1,18 @@
+require 'rubygems'
+require 'lib/tropo-provisioning'
+
+config = YAML.load(File.open('examples/config.yml'))
+app_details = YAML.load(File.open("examples/#{config['filename']}"))
+
+# Create a new provisioning object with your Tropo credentials
+provisioning = TropoProvisioning.new(config['tropo']['username'], config['tropo']['password'])
+
+# Then you may iterate through all of your configured addresses
+provisioning.addresses(app_details.application_id).each do |address|
+ p address
+ puts '*'*10
+end
+
+# Then, lets fetch a single address where the first param is the application ID and the second the associated address ID
+p provisioning.address(app_details.application_id, '883510001812716')
+p provisioning.address(app_details.application_id, 'xyz123')
17 examples/list_applications.rb
@@ -0,0 +1,17 @@
+require 'rubygems'
+require 'lib/tropo-provisioning'
+
+config = YAML.load(File.open('examples/config.yml'))
+app_details = YAML.load(File.open("examples/#{config['filename']}"))
+
+# Create a new provisioning object with your Tropo credentials
+provisioning = TropoProvisioning.new(config['tropo']['username'], config['tropo']['password'])
+
+# Then you may iterate through all of your configured applications
+provisioning.applications.each do |app|
+ p app
+ puts '*'*10
+end
+
+# Now list a single application
+p provisioning.application(app_details.application_id)
13 examples/list_exchanges.rb
@@ -0,0 +1,13 @@
+require 'rubygems'
+require 'lib/tropo-provisioning'
+
+config = YAML.load(File.open('examples/config.yml'))
+
+# Create a new provisioning object with your Tropo credentials
+provisioning = TropoProvisioning.new(config['tropo']['username'], config['tropo']['password'])
+
+# Then you may iterate through all of the available exchanges
+provisioning.exchanges.each do |exchange|
+ p exchange
+ puts '*'*10
+end
0  examples/list_pin.rb
No changes.
17 examples/update_application.rb
@@ -0,0 +1,17 @@
+require 'rubygems'
+require 'lib/tropo-provisioning'
+
+config = YAML.load(File.open('examples/config.yml'))
+app_details = YAML.load(File.open("examples/#{config['filename']}"))
+
+# Create a new provisioning object with your Tropo credentials
+provisioning = TropoProvisioning.new(config['tropo']['username'], config['tropo']['password'])
+
+# First, get the application in question
+application = provisioning.application(app_details.application_id)
+
+# Set the name we want to change to
+application['name'] = 'My Awesome App'
+
+# Then create the application you would like to
+p provisioning.update_application(app_details.application_id, application)
2  lib/tropo-provisioning.rb
@@ -0,0 +1,2 @@
+$: << File.expand_path(File.dirname(__FILE__))
+%w(net/http uri active_support/json active_support/inflector hashie tropo-provisioning/tropo-provisioning).each { |lib| require lib }
303 lib/tropo-provisioning/tropo-provisioning.rb
@@ -0,0 +1,303 @@
+class TropoProvisioning
+
+ # Defaults for the creation of applications
+ DEFAULT_OPTIONS = { :partition => 'staging', :platform => 'scripting' }
+ ##
+ # Creates a new TropoProvisioning object
+ #
+ # @param [required, String] username for your Tropo account
+ # @param [required, String] password for your Tropo account
+ # @param [optional, Hash] params
+ # @option params [optional, String] :base_uri to use for accessing the provisioning API if you would like a custom one
+ # @return [Object] a TropoProvisioning object
+ def initialize(username, password, params={})
+ @username = username
+ @password = password
+
+ if params[:base_uri]
+ @base_uri = params[:base_uri]
+ else
+ @base_uri = "http://api.tropo.com/provisioning"
+ end
+
+ @headers = { 'Content-Type' => 'application/json' }
+ end
+
+ ##
+ # Adds an address to an existing application
+ #
+ # @param [required, String] application_id to add the address to
+ # @param [required, Hash] params the parameters used to request the address
+ # @option params [String] :type this defines the type of address. The possibles types are number (phone numbers), pin (reserved), token, aim, jabber, msn, yahoo, gtalk & skype
+ # @option params [String] :prefix this defines the country code and area code for phone numbers
+ # @option params [String] :username the messaging/IM account's username
+ # @option params [String] :password the messaging/IM account's password
+ # @return [Hash] the href that identifies the address that was added, refer to address method for details
+ def add_address(application_id, params={})
+ raise ArgumentError, ':type required' unless params[:type]
+
+ case params[:type].downcase
+ when 'number'
+ raise ArgumentError, ':prefix required to add a number address' unless params[:prefix] || params[:number]
+ when 'aim', 'msn', 'yahoo', 'gtalk'
+ raise ArgumentError, ':username and required' unless params[:username]
+ raise ArgumentError, ':password and required' unless params[:password]
+ when 'jabber'
+ raise ArgumentError, ':username required' unless params[:username]
+ when 'token'
+ raise ArgumentError, ':channel required' unless params[:channel]
+ raise ArgumentError, ':channel must be voice or messaging' unless params[:channel] == 'voice' || params[:channel] == 'messaging'
+ end
+
+ response = request(:post, { :resource => 'applications/' + application_id.to_s + '/addresses', :body => params })
+ end
+
+ ##
+ # Get a specific application
+ #
+ # @param [required, String] application_id of the application to get
+ # @return [Hash] params the key/values that make up the application
+ # @option params [String] :href the REST address for the application
+ # @option params [String] :name the name of the application
+ # @option params [String] :voiceUrl the URL that powers voice calls for your application
+ # @option params [String] :messagingUrl the URL that powers the SMS/messaging calls for your session
+ # @option params [String] :platform defines whether the application will use the Scripting API or the Web API
+ # @option params [String] :partition defines whether the application is in staging/development or production
+ def application(application_id)
+ result = request(:get, { :resource => 'applications/' + application_id.to_s })
+ end
+
+ ##
+ # Fetches all of the applications configured for an account
+ #
+ # @return [Hash] contains the results of the inquiry with a list of applications for the authenticated account, refer to the application method for details
+ def applications
+ results = request(:get, { :resource => 'applications' })
+ result_with_ids = []
+ results.each do |app|
+ result_with_ids << app.merge!({ :application_id => get_application_id(app.href) })
+ end
+ result_with_ids
+ end
+
+ ##
+ # Create a new application
+ #
+ # @param [required, Hash] params to create the application
+ # @option params [required, String] :name the name to assign to the application
+ # @option params [required, String] :partition this defines whether the application is in staging/development or production
+ # @option params [required, String] :platform (scripting) whehter to use scripting or the webapi
+ # @option params [required, String] :messagingUrl or :messaging_url The URL that powers the SMS/messages sessions for your application
+ # @option params [required, String] :voiceUrl or :voice_url the URL that powers voices calls for your application
+ # @return [Hash] returns the href of the application created and the application_id of the application created
+ def create_application(params={})
+ merged_params = DEFAULT_OPTIONS.merge(camelize_params(params))
+ validate_params merged_params
+ result = request(:post, { :resource => 'applications', :body => params })
+ result[:application_id] = get_application_id(result.href)
+ result
+ end
+
+ ##
+ # Deletes an application
+ #
+ # @param [required, String] application_id to be deleted
+ # @return [Hash] not sure since it does 204 now, need to check with Cervantes, et al
+ def delete_application(application_id)
+ request(:delete, { :resource => 'applications/' + application_id.to_s })
+ end
+
+ ##
+ # Deletes a address from a specific application
+ #
+ # @param [String] application_id that the address is associated to
+ # @param [String] address_id for the address
+ def delete_address(application_id, address_id)
+ address_to_delete = address(application_id, address_id)
+ request(:delete, { :resource => 'applications/' + application_id.to_s + '/addresses/' + address_to_delete['type'] + '/' + address_id.to_s })
+ end
+
+ ##
+ # Provides a list of available exchanges to obtain Numbers from
+ #
+ # @return [Array] the list of available exchanges
+ def exchanges
+ request(:get, { :resource => 'exchanges' })
+ end
+
+ ##
+ # Used to move a address between one application and another
+ #
+ # @param [Hash] params contains a hash of the applications and address to move
+ # @option params [required, String] :from
+ # @option params [required, String] :to
+ # @option params [required, String] :address
+ def move_address(params={})
+ raise ArgumentError, ':from is required' unless params[:from]
+ raise ArgumentError, ':to is required' unless params[:to]
+ raise ArgumentError, ':address is required' unless params[:address]
+
+ begin
+ address_to_move = address(params[:from], params[:address])
+ delete_address(params[:from], params[:address])
+ request(:post, { :resource => 'applications/' + params[:to] + '/addresses/' + address_to_move['type'] + '/' + params[:address]})
+ rescue
+ raise RuntimeError, 'Unable to move the address'
+ end
+ end
+
+ ##
+ # Get a specific address for an application
+ #
+ # @param [required, String] application_id to obtain the address for
+ # @param [required, String] address_id of the address to obtain the details for
+ # @return [Hash] the details of the address
+ # @option params [String] :href the REST address for the application
+ # @option params [String] :name the name of the application
+ # @option params [String] :voiceUrl the URL that powers voices calls for your application
+ # @option params [String] :messagingUrl The URL that powers the SMS/messages sessions for your application
+ # @option params [String] :partition this defines whether the application is in staging/development or production
+ # @option params [String] :type this defines the type of address. The possibles types are number (phone numbers), pin (reserved), token, aim, jabber, msn, yahoo, gtalk & skype
+ # @option params [String] :prefix this defines the country code and area code for phone numbers
+ # @option params [String] :number the phone number assigned to the application
+ # @option params [String] :city the city associated with the assigned phone number
+ # @option params [String] :state the state associated with the assigned phone number
+ # @option params [String] :channel idenifites the type of channel, maybe 'voice' or 'messaging'
+ # @option params [String] :username the messaging/IM account's username
+ # @option params [String] :password the messaging/IM account's password
+ # @option params [String] :token alphanumeric string that identifies your Tropo application, used with the Session API
+ def address(application_id, address_id)
+ addresses(application_id).each { |address| return address if address['number'] == address_id ||
+ address['username'] == address_id ||
+ address['pin'] == address_id ||
+ address['token'] == address_id }
+ raise RuntimeError, 'Address not found with that application.'
+ end
+
+ ##
+ # Get all of the configured addresses for an application
+ #
+ # @param [required, String] application_id to fetch the addresses for
+ # @return [Hash] all of the addresses configured for the application
+ def addresses(application_id)
+ request(:get, { :resource => 'applications/' + application_id.to_s + '/addresses' })
+ end
+
+ ##
+ # Updated an existing application
+ #
+ # @param [required, String] the application id to update
+ # @param [required, Hash] params the parameters used to create the application
+ # @option params [optional, String] :name the name of the application
+ # @option params [optional, String] :voiceUrl the URL that powers voices calls for your application
+ # @option params [optional, String] :messagingUrl The URL that powers the SMS/messages sessions for your application
+ # @option params [optional, String] :partition whether to create in staging or production
+ # @option params [optional, String] :platform whehter to use scripting or the webapi
+ # @return [Hash] returns the href of the application created
+ def update_application(application_id, params={})
+ request(:put, { :resource => 'applications/' + application_id.to_s, :body => params })
+ end
+
+ private
+
+ ##
+ #
+ def camelize_params(params)
+ camelized = {}
+ params.each { |k,v| camelized.merge!(k.to_s.camelize(:lower).to_sym => v) }
+ camelized
+ end
+
+ ##
+ # Converts the hashes inside the array to Hashie::Mash objects
+ #
+ # @param [required, Array] array to be Hashied
+ # @param [Array] array that is now Hashied
+ def hashie_array(array)
+ hashied_array = []
+ array.each do |ele|
+ hashied_array << Hashie::Mash.new(ele)
+ end
+ hashied_array
+ end
+
+ ##
+ # Parses the URL and returns the application ID
+ #
+ # @param [required, String] the URL to parse for the application ID
+ # @return [String] the application id parsed from the URL
+ def get_application_id(url)
+ url.split('/').last
+ end
+
+ ##
+ # Creates the appropriate URI and HTTP handlers for our request
+ #
+ # @param [required, Symbol] the HTTP action to use :delete, :get, :post or :put
+ # @param [required, Hash] params used to create the request
+ # @option params [String] :resource the resource to call on the base URL
+ # @option params [Hash] :body the details to use when posting, putting or deleting an object, converts into the appropriate JSON
+ # @return [Hash] the result of the request
+ def request(method, params={})
+ if params[:resource]
+ uri = URI.parse(@base_uri + '/' + params[:resource])
+ else
+ uri = URI.parse(@base_uri)
+ end
+ http = Net::HTTP.new(uri.host, uri.port)
+
+ request = set_request_type(method, uri)
+ request.initialize_http_header(@headers)
+ request.basic_auth @username, @password
+ request.body = ActiveSupport::JSON.encode params[:body] if params[:body]
+
+ response = http.request(request)
+ raise RuntimeError, "#{response.code} - #{response.message}" unless response.code == '200'
+
+ result = ActiveSupport::JSON.decode response.body
+ if result.instance_of? Array
+ hashie_array(result)
+ else
+ Hashie::Mash.new(result)
+ end
+ end
+
+ ##
+ # Sets the HTTP REST type based on the method being called
+ #
+ # @param [required, ymbol] the HTTP method to use, may be :delete, :get, :post or :put
+ # @param [Object] the uri object to create the request for
+ # @return [Object] the request object to be used to operate on the resource
+ def set_request_type(method, uri)
+ case method
+ when :delete
+ Net::HTTP::Delete.new(uri.request_uri)
+ when :get
+ Net::HTTP::Get.new(uri.request_uri)
+ when :post
+ Net::HTTP::Post.new(uri.request_uri)
+ when :put
+ Net::HTTP::Put.new(uri.request_uri)
+ end
+ end
+
+ ##
+ # Validates that we have all of the appropriate params when creating an application
+ #
+ # @param [Hash] params to create the application
+ # @option params [required, String] :name the name to assign to the application
+ # @option params [required, String] :partition whether to create in staging or production
+ # @option params [required, String] :platform whehter to use scripting or the webapi
+ # @option params [String] :messagingUrl the Url to use for handiling messaging requests
+ # @option params [String] :voiceUrl the Url to use for handling voice requests
+ # @return nil
+ def validate_params(params={})
+ # Make sure all of the arguments are present
+ raise ArgumentError, ':name required' unless params[:name]
+ raise ArgumentError, ':messagingUrl or :voiceUrl required' unless params[:messagingUrl] || params[:voiceUrl]
+
+ # Make sure the arguments have valid values
+ raise ArgumentError, ":platform must be 'scripting' or 'webapi'" unless params[:platform] == 'scripting' || params[:platform] == 'webapi'
+ raise ArgumentError, ":partiion must be 'staging' or 'production'" unless params[:partition] == 'staging' || params[:partition] == 'production'
+ end
+end
75 spec/live-tropo-provisioning_spec.rb
@@ -0,0 +1,75 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+describe "TropoProvisioning" do
+ before(:all) do
+ @app_details = { :voiceUrl => 'http://mydomain.com/voice_script.rb',
+ :partition => 'staging',
+ :messagingUrl => 'http://mydomain.com/message_script.rb',
+ :platform => 'scripting' }
+ @tp = TropoProvisioning.new('jsgoecke', 'test123')
+ end
+
+ it "should create an application" do
+ result = @tp.create_application(@app_details.merge!({ :name => 'Live API Test' }))
+ result.href.should =~ /^http:\/\/api.tropo.com\/provisioning\/applications\/\d{1,7}$/
+ result.application_id.should =~ /\d{1,7}/
+ APPLICATION_ID = result.application_id
+ end
+
+ it "should get a list of exchanges" do
+ exchanges = @tp.exchanges
+ exchanges[0].city.should == 'Houston'
+ end
+
+ it "should add a phone, IM and token address to the application" do
+ result = @tp.add_address(APPLICATION_ID, { :type => 'number', :prefix => @tp.exchanges[0].prefix })
+ result.href.should =~ /http:\/\/api.tropo.com\/provisioning\/applications\/\d{1,7}\/addresses\/number\/\d{1,20}/
+
+ result = @tp.add_address(APPLICATION_ID, { :type => 'jabber', :username => "liveapitest#{rand(100000).to_s}@bot.im" } )
+ result.href.should =~ /http:\/\/api.tropo.com\/provisioning\/applications\/\d{1,7}\/addresses\/jabber\/\w{10,16}@bot.im/
+
+ result = @tp.add_address(APPLICATION_ID, { :type => 'token', :channel => 'voice' } )
+ result.href.should =~ /http:\/\/api.tropo.com\/provisioning\/applications\/\d{1,7}\/addresses\/token\/\w{88}/
+ end
+
+ it "should update the application" do
+ # First, get the application in question
+ app_data = @tp.application(APPLICATION_ID)
+ app_data['name'] = 'Live API Test Update'
+ result = @tp.update_application(APPLICATION_ID, app_data)
+ result.href.should =~ /^http:\/\/api.tropo.com\/provisioning\/applications\/\d{1,7}$/
+ end
+
+ # it "should move a address to a new application and then back" do
+ # new_app = @tp.create_application(@app_details.merge!({ :name => 'Live API Test New' }))
+ # new_app.href.should =~ /^http:\/\/api.tropo.com\/provisioning\/applications\/\d{1,7}$/
+ #
+ # addresses = @tp.addresses(APPLICATION_ID)
+ # addresses[0].address.should =~ /\d{10}@sip.tropo.com/
+ # p addresses
+ # result = @tp.move_address({ :from => APPLICATION_ID,
+ # :to => new_app,
+ # :address => addresses[0].number })
+ # result.should == nil
+ #
+ # result = @tp.move_address({ :from => new_app,
+ # :to => APPLICATION_ID,
+ # :address => addresses[0]['number'] })
+ # result.should == nil
+ # end
+
+ # it "should delete the addresses of an application" do
+ # addresses = @tp.addresses(APPLICATION_ID)
+ # addresses.each do |address|
+ # result = @tp.delete_address(APPLICATION_ID, address['number']) if address['number']
+ # result.message.should == 'delete successful'
+ # result = @tp.delete_address(APPLICATION_ID, address['username']) if address['username']
+ # result.message.should == 'delete successful'
+ # end
+ # end
+ #
+ # it "should delete an application" do
+ # result = @tp.delete_application(APPLICATION_ID)
+ # result.message.should == 'delete successful'
+ # end
+end
11 spec/spec_helper.rb
@@ -0,0 +1,11 @@
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+require 'tropo-provisioning'
+require 'rspec'
+require 'rspec/autorun'
+require 'fakeweb'
+require 'active_support/json'
+
+RSpec.configure do |config|
+
+end
436 spec/tropo-provisioning_spec.rb
@@ -0,0 +1,436 @@
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+
+# These tests are all local unit tests
+FakeWeb.allow_net_connect = false
+
+describe "TropoProvisioning" do
+ before(:all) do
+ @applications = [ { "voiceUrl" => "http://webhosting.voxeo.net/1234/www/simple.js",
+ "name" => "API Test",
+ "href" => "http://api.tropo.com/provisioning/applications/108000",
+ "partition" => "staging",
+ "platform" => "scripting" },
+ { "voiceUrl" => "http://hosting.tropo.com/1234/www/simon.rb",
+ "name" => "Simon Game",
+ "href" => "http://api.tropo.com/provisioning/applications/105838",
+ "partition" => "staging",
+ "messagingUrl" => "http://hosting.tropo.com/1234/www/simon.rb",
+ "platform" => "scripting" },
+ { "voiceUrl" => "http://webhosting.voxeo.net/1234/www/simple.js",
+ "name" => "Foobar",
+ "href" => "http://api.tropo.com/provisioning/applications/108002",
+ "partition" => "staging",
+ "platform" => "scripting" } ]
+
+ @addresses = [ { "region" => "I-US",
+ "city" => "iNum US",
+ "number" => "883510001812716",
+ "href" => "http://api.tropo.com/provisioning/applications/108000/addresses/number/883510001812716",
+ "prefix" => "008",
+ "type" => "number" },
+ { "number" => "9991436301",
+ "href" => "http://api.tropo.com/provisioning/applications/108000/addresses/pin/9991436300",
+ "type" => "pin" },
+ { "href" => "http://api.tropo.com/provisioning/applications/108000/addresses/jabber/xyz123",
+ "nickname" => "",
+ "username" => "xyz123",
+ "type" => "jabber" },
+ { "href" => "http://api.tropo.com/provisioning/applications/108000/addresses/jabber/xyz123",
+ "nickname" => "",
+ "username" => "9991436300",
+ "type" => "pin" },
+ { "href" => "http://api.tropo.com/provisioning/applications/108000/addresses/token/a1b2c3d4",
+ "nickname" => "",
+ "username" => "a1b2c3d4",
+ "type" => "token" } ]
+
+ @exchanges = '[
+ {
+ "prefix":"1407",
+ "city":"Orlando",
+ "state":"FL",
+ "country": "United States"
+ },
+ {
+ "prefix":"1312",
+ "city":"Chicago",
+ "state":"IL",
+ "country":"United States"
+ },
+ {
+ "prefix":"1303",
+ "city":"Denver",
+ "state":"CO",
+ "country":"United States"
+ },
+ {
+ "prefix":"1310",
+ "city": "Los Angeles",
+ "state":"CA",
+ "country":"United States"
+ },
+ {
+ "prefix": "1412",
+ "city":"Pittsburgh",
+ "state":"PA",
+ "country": "United States"
+ },
+ {
+ "prefix":"1415",
+ "city":"San Francisco",
+ "state": "CA",
+ "country":"United States"
+ },
+ {
+ "prefix":"1206",
+ "city": "Seattle",
+ "state":"WA",
+ "country":"United States"
+ },
+ {
+ "prefix": "1301",
+ "city":"Washington",
+ "state":"DC",
+ "country": "United States"
+ }
+ ]'
+
+ # Register our resources
+
+ # Applications with a bad uname/passwd
+ FakeWeb.register_uri(:get,
+ %r|http://bad:password@api.tropo.com/provisioning/applications|,
+ :status => ["401", "Unauthorized"])
+
+ # A specific application
+ FakeWeb.register_uri(:get,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000",
+ :body => ActiveSupport::JSON.encode(@applications[0]),
+ :content_type => "application/json")
+
+ # Applications
+ FakeWeb.register_uri(:get,
+ %r|http://foo:bar@api.tropo.com/provisioning/applications|,
+ :body => ActiveSupport::JSON.encode(@applications),
+ :content_type => "application/json")
+
+ # Create an application
+ FakeWeb.register_uri(:post,
+ %r|http://foo:bar@api.tropo.com/provisioning/applications|,
+ :body => ActiveSupport::JSON.encode({ "href" => "http://api.tropo.com/provisioning/applications/108016" }),
+ :status => ["200", "OK"])
+
+ # Update a specific application
+ FakeWeb.register_uri(:put,
+ %r|http://foo:bar@api.tropo.com/provisioning/applications/108000|,
+ :body => ActiveSupport::JSON.encode({ "href" => "http://api.tropo.com/provisioning/applications/108016" }),
+ :status => ["200", "OK"])
+
+ # Addresses
+ FakeWeb.register_uri(:get,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000/addresses",
+ :body => ActiveSupport::JSON.encode(@addresses),
+ :content_type => "application/json")
+
+ # Get a specific address
+ FakeWeb.register_uri(:get,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000/addresses/number/883510001812716",
+ :body => ActiveSupport::JSON.encode(@addresses[0]),
+ :content_type => "application/json")
+
+ # Get a address that is an IM/username
+ FakeWeb.register_uri(:get,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000/addresses/jabber/xyz123",
+ :body => ActiveSupport::JSON.encode(@addresses[2]),
+ :content_type => "application/json")
+
+ # Get a address that is a token
+ FakeWeb.register_uri(:get,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000/addresses/jabber/xyz123",
+ :body => ActiveSupport::JSON.encode(@addresses[2]),
+ :content_type => "application/json")
+
+ # Get a address that is a Pin
+ FakeWeb.register_uri(:post,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000/addresses",
+ :body => ActiveSupport::JSON.encode(@addresses[2]),
+ :content_type => "application/json")
+
+ # Get a address that is a token
+ FakeWeb.register_uri(:get,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000/addresses/token/a1b2c3d4",
+ :body => ActiveSupport::JSON.encode(@addresses[4]),
+ :content_type => "application/json")
+
+ # Get a address that is a number
+ FakeWeb.register_uri(:post,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000/addresses",
+ :body => ActiveSupport::JSON.encode({ "href" => "http://api.tropo.com/provisioning/applications/108000/addresses/number/7202551912" }),
+ :content_type => "application/json")
+
+ # Create a address that is an IM account
+ FakeWeb.register_uri(:post,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108001/addresses",
+ :body => ActiveSupport::JSON.encode({ "href" => "http://api.tropo.com/provisioning/applications/108001/addresses/jabber/xyz123@bot.im" }),
+ :content_type => "application/json")
+
+ # Create a address that is a Token
+ FakeWeb.register_uri(:post,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108002/addresses",
+ :body => ActiveSupport::JSON.encode({ "href" => "http://api.tropo.com/provisioning/applications/108002/addresses/token/12345679f90bac47a05b178c37d3c68aaf38d5bdbc5aba0c7abb12345d8a9fd13f1234c1234567dbe2c6f63b" }),
+ :content_type => "application/json")
+
+ # Delete an application
+ FakeWeb.register_uri(:delete,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000",
+ :body => ActiveSupport::JSON.encode({ 'message' => 'delete successful' }),
+ :content_type => "application/json",
+ :status => ["200", "OK"])
+
+ # Exchanges
+ FakeWeb.register_uri(:get,
+ "http://foo:bar@api.tropo.com/provisioning/exchanges",
+ :body => @exchanges,
+ :status => ["200", "OK"],
+ :content_type => "application/json")
+
+ # Delete a address
+ FakeWeb.register_uri(:delete,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108000/addresses/number/883510001812716",
+ :body => ActiveSupport::JSON.encode({ 'message' => 'delete successful' }),
+ :content_type => "application/json",
+ :status => ["200", "OK"])
+
+ # Add a specific address
+ FakeWeb.register_uri(:post,
+ "http://foo:bar@api.tropo.com/provisioning/applications/108002/addresses/number/883510001812716",
+ :body => ActiveSupport::JSON.encode({ 'message' => 'delete successful' }),
+ :content_type => "application/json",
+ :status => ["200", "OK"])
+ end
+
+ before(:each) do
+ @tropo_provisioning = TropoProvisioning.new('foo', 'bar')
+ end
+
+ it "should create a TropoProvisioning object" do
+ @tropo_provisioning.instance_of?(TropoProvisioning).should == true
+ end
+
+ it "should get an unathorized back if there is an invalid username or password" do
+ bad_credentials = TropoProvisioning.new('bad', 'password')
+ begin
+ response = bad_credentials.applications
+ rescue => e
+ e.to_s.should == '401 - Unauthorized'
+ end
+ end
+
+ it "should get a list of applications" do
+ applications = []
+ @applications.each { |app| applications << app.merge({ 'application_id' => app['href'].split('/').last }) }
+
+ @tropo_provisioning.applications.should == applications
+ end
+
+ it "should get a specific application" do
+ response = @tropo_provisioning.application '108000'
+ response.should == @applications[0]
+ end
+
+ it "should raise ArgumentErrors if appropriate arguments are not specified" do
+ begin
+ @tropo_provisioning.create_application({ :foo => 'bar' })
+ rescue => e
+ e.to_s.should == ':name required'
+ end
+
+ begin
+ @tropo_provisioning.create_application({ :name => 'foobar',
+ :partition => 'foobar',
+ :platform => 'foobar' })
+ rescue => e
+ e.to_s.should == ':messagingUrl or :voiceUrl required'
+ end
+ end
+
+ it "should raise ArgumentErrors if appropriate values are not passed" do
+ begin
+ @tropo_provisioning.create_application({ :name => 'foobar',
+ :partition => 'foobar',
+ :platform => 'foobar',
+ :messagingUrl => 'http://foobar' })
+ rescue => e
+ e.to_s.should == ":platform must be 'scripting' or 'webapi'"
+ end
+
+ begin
+ @tropo_provisioning.create_application({ :name => 'foobar',
+ :partition => 'foobar',
+ :platform => 'scripting',
+ :messagingUrl => 'http://foobar' })
+ rescue => e
+ e.to_s.should == ":partiion must be 'staging' or 'production'"
+ end
+ end
+
+ it "should receive an href back when we create a new application receiving an href back" do
+ # With camelCase
+ result = @tropo_provisioning.create_application({ :name => 'foobar',
+ :partition => 'production',
+ :platform => 'scripting',
+ :messagingUrl => 'http://foobar' })
+ result.href.should == "http://api.tropo.com/provisioning/applications/108016"
+ result.application_id.should == '108016'
+
+ # With underscores
+ result = @tropo_provisioning.create_application({ :name => 'foobar',
+ :partition => 'production',
+ :platform => 'scripting',
+ :messaging_url => 'http://foobar' })
+ result.href.should == "http://api.tropo.com/provisioning/applications/108016"
+ result.application_id.should == '108016'
+ end
+
+ it "should receive an href back when we update an application receiving an href back" do
+ # With camelCase
+ result = @tropo_provisioning.update_application('108000', { :name => 'foobar',
+ :partition => 'production',
+ :platform => 'scripting',
+ :messagingUrl => 'http://foobar' })
+ result.href.should == "http://api.tropo.com/provisioning/applications/108016"
+
+ # With underscore
+ result = @tropo_provisioning.update_application('108000', { :name => 'foobar',
+ :partition => 'production',
+ :platform => 'scripting',
+ :messaging_url => 'http://foobar' })
+ result.href.should == "http://api.tropo.com/provisioning/applications/108016"
+ end
+
+ it "should delete an application" do
+ result = @tropo_provisioning.delete_application('108000')
+ result.message.should == 'delete successful'
+ end
+
+ it "should list all of the addresses available for an application" do
+ result = @tropo_provisioning.addresses('108000')
+ result.should == @addresses
+ end
+
+ it "should list a single address when requested with a number for numbers" do
+ result = @tropo_provisioning.address('108000', '883510001812716')
+ result.should == @addresses[0]
+ end
+
+ it "should list a single address of the appropriate type when requested" do
+ # First a number
+ result = @tropo_provisioning.address('108000', '883510001812716')
+ result.should == @addresses[0]
+
+ # Then an IM username
+ result = @tropo_provisioning.address('108000', 'xyz123')
+ result.should == @addresses[2]
+
+ # Then a pin
+ result = @tropo_provisioning.address('108000', '9991436300')
+ result.should == @addresses[3]
+
+ # Then a token
+ result = @tropo_provisioning.address('108000', 'a1b2c3d4')
+ result.should == @addresses[4]
+ end
+
+ it "should generate an error of the addition of the address does not have a required field" do
+ # Add a address without a type
+ begin
+ @tropo_provisioning.add_address('108000')
+ rescue => e
+ e.to_s.should == ":type required"
+ end
+
+ # Add a number without a prefix
+ begin
+ @tropo_provisioning.add_address('108000', { :type => 'number' })
+ rescue => e
+ e.to_s.should == ":prefix required to add a number address"
+ end
+
+ # Add a jabber without a username
+ begin
+ @tropo_provisioning.add_address('108000', { :type => 'jabber' })
+ rescue => e
+ e.to_s.should == ":username required"
+ end
+
+ # Add an aim without a password
+ begin
+ @tropo_provisioning.add_address('108000', { :type => 'aim', :username => 'joeblow@aim.com' })
+ rescue => e
+ e.to_s.should == ":password and required"
+ end
+
+ # Add a token without a channel
+ begin
+ @tropo_provisioning.add_address('108000', { :type => 'token' })
+ rescue => e
+ e.to_s.should == ":channel required"
+ end
+
+ # Add a token with an invalid channel type
+ begin
+ @tropo_provisioning.add_address('108000', { :type => 'token', :channel => 'BBC' })
+ rescue => e
+ e.to_s.should == ":channel must be voice or messaging"
+ end
+ end
+
+ it "should add appropriate addresses" do
+ # Add a address based on a prefix
+ result = @tropo_provisioning.add_address('108000', { :type => 'number', :prefix => '1303' })
+ result[:href].should == "http://api.tropo.com/provisioning/applications/108000/addresses/number/7202551912"
+
+ # Add a jabber account
+ result = @tropo_provisioning.add_address('108001', { :type => 'jabber', :username => 'xyz123@bot.im' })
+ result[:href].should == "http://api.tropo.com/provisioning/applications/108001/addresses/jabber/xyz123@bot.im"
+
+ # Add a token
+ result = @tropo_provisioning.add_address('108002', { :type => 'token', :channel => 'voice' })
+ result[:href].should == "http://api.tropo.com/provisioning/applications/108002/addresses/token/12345679f90bac47a05b178c37d3c68aaf38d5bdbc5aba0c7abb12345d8a9fd13f1234c1234567dbe2c6f63b"
+ end
+
+ it "should obtain a list of available exchanges" do
+ results = @tropo_provisioning.exchanges
+ results.should == ActiveSupport::JSON.decode(@exchanges)
+ end
+
+ it "should delete a address" do
+ result = @tropo_provisioning.delete_address('108000', '883510001812716')
+ result[:message].should == "delete successful"
+ end
+
+ it "should raise an ArgumentError if the right params are not passed to move_address" do
+ begin
+ @tropo_provisioning.move_address({ :to => '108002', :address => '883510001812716'})
+ rescue => e
+ e.to_s.should == ':from is required'
+ end
+
+ begin
+ @tropo_provisioning.move_address({ :from => '108002', :address => '883510001812716'})
+ rescue => e
+ e.to_s.should == ':to is required'
+ end
+
+ begin
+ @tropo_provisioning.move_address({ :from => '108002', :to => '883510001812716'})
+ rescue => e
+ e.to_s.should == ':address is required'
+ end
+ end
+
+ it "should move a address" do
+ results = @tropo_provisioning.move_address({ :from => '108000', :to => '108002', :address => '883510001812716'})
+ results.should == { 'message' => 'delete successful' }
+ end
+end
80 tropo-provisioning.gemspec
@@ -0,0 +1,80 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{tropo-provisioning}
+ s.version = "0.0.1"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Jason Goecke"]
+ s.date = %q{2010-07-28}
+ s.description = %q{Library for interacting with the Tropo Provisioning API}
+ s.email = %q{jsgoecke@voxeo.com}
+ s.extra_rdoc_files = [
+ "LICENSE",
+ "README.rdoc"
+ ]
+ s.files = [
+ ".gitignore",
+ "LICENSE",
+ "README.rdoc",
+ "Rakefile",
+ "VERSION",
+ "examples/add_addresses.rb",
+ "examples/config.yml",
+ "examples/create_application.rb",
+ "examples/delete_application.rb",
+ "examples/list_addresses.rb",
+ "examples/list_applications.rb",
+ "examples/list_exchanges.rb",
+ "examples/list_pin.rb",
+ "examples/update_application.rb",
+ "lib/tropo-provisioning.rb",
+ "lib/tropo-provisioning/tropo-provisioning.rb",
+ "spec/live-tropo-provisioning_spec.rb",
+ "spec/spec.opts",
+ "spec/spec_helper.rb",
+ "spec/tropo-provisioning_spec.rb",
+ "tropo-provisioning.gemspec"
+ ]
+ s.homepage = %q{http://github.com/voxeo/tropo-provisioning}
+ s.rdoc_options = ["--charset=UTF-8"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.3.7}
+ s.summary = %q{Library for interacting with the Tropo Provisioning API}
+ s.test_files = [
+ "spec/live-tropo-provisioning_spec.rb",
+ "spec/spec_helper.rb",
+ "spec/tropo-provisioning_spec.rb",
+ "examples/add_addresses.rb",
+ "examples/create_application.rb",
+ "examples/delete_application.rb",
+ "examples/list_addresses.rb",
+ "examples/list_applications.rb",
+ "examples/list_exchanges.rb",
+ "examples/list_pin.rb",
+ "examples/update_application.rb"
+ ]
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
+ s.add_runtime_dependency(%q<hashie>, [">= 0.2.1"])
+ s.add_runtime_dependency(%q<activesupport>)
+ else
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
+ s.add_dependency(%q<hashie>, [">= 0.2.1"])
+ s.add_dependency(%q<activesupport>)
+ end
+ else
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
+ s.add_dependency(%q<hashie>, [">= 0.2.1"])
+ s.add_dependency(%q<activesupport>)
+ end
+end
+
Please sign in to comment.
Something went wrong with that request. Please try again.