braintree 1.0.0
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.
- data/LICENSE +22 -0
 - data/README.rdoc +62 -0
 - data/lib/braintree.rb +66 -0
 - data/lib/braintree/address.rb +122 -0
 - data/lib/braintree/base_module.rb +29 -0
 - data/lib/braintree/configuration.rb +99 -0
 - data/lib/braintree/credit_card.rb +231 -0
 - data/lib/braintree/credit_card_verification.rb +31 -0
 - data/lib/braintree/customer.rb +231 -0
 - data/lib/braintree/digest.rb +20 -0
 - data/lib/braintree/error_codes.rb +95 -0
 - data/lib/braintree/error_result.rb +39 -0
 - data/lib/braintree/errors.rb +29 -0
 - data/lib/braintree/http.rb +105 -0
 - data/lib/braintree/paged_collection.rb +55 -0
 - data/lib/braintree/ssl_expiration_check.rb +28 -0
 - data/lib/braintree/successful_result.rb +38 -0
 - data/lib/braintree/test/credit_card_numbers.rb +50 -0
 - data/lib/braintree/test/transaction_amounts.rb +10 -0
 - data/lib/braintree/transaction.rb +360 -0
 - data/lib/braintree/transaction/address_details.rb +15 -0
 - data/lib/braintree/transaction/credit_card_details.rb +22 -0
 - data/lib/braintree/transaction/customer_details.rb +13 -0
 - data/lib/braintree/transparent_redirect.rb +110 -0
 - data/lib/braintree/util.rb +94 -0
 - data/lib/braintree/validation_error.rb +15 -0
 - data/lib/braintree/validation_error_collection.rb +80 -0
 - data/lib/braintree/version.rb +9 -0
 - data/lib/braintree/xml.rb +12 -0
 - data/lib/braintree/xml/generator.rb +80 -0
 - data/lib/braintree/xml/libxml.rb +69 -0
 - data/lib/braintree/xml/parser.rb +93 -0
 - data/lib/ssl/securetrust_ca.crt +44 -0
 - data/lib/ssl/valicert_ca.crt +18 -0
 - data/spec/integration/braintree/address_spec.rb +352 -0
 - data/spec/integration/braintree/credit_card_spec.rb +676 -0
 - data/spec/integration/braintree/customer_spec.rb +664 -0
 - data/spec/integration/braintree/http_spec.rb +201 -0
 - data/spec/integration/braintree/test/transaction_amounts_spec.rb +29 -0
 - data/spec/integration/braintree/transaction_spec.rb +900 -0
 - data/spec/integration/spec_helper.rb +38 -0
 - data/spec/script/httpsd.rb +27 -0
 - data/spec/spec_helper.rb +41 -0
 - data/spec/unit/braintree/address_spec.rb +86 -0
 - data/spec/unit/braintree/configuration_spec.rb +190 -0
 - data/spec/unit/braintree/credit_card_spec.rb +137 -0
 - data/spec/unit/braintree/credit_card_verification_spec.rb +17 -0
 - data/spec/unit/braintree/customer_spec.rb +103 -0
 - data/spec/unit/braintree/digest_spec.rb +28 -0
 - data/spec/unit/braintree/error_result_spec.rb +42 -0
 - data/spec/unit/braintree/errors_spec.rb +81 -0
 - data/spec/unit/braintree/http_spec.rb +42 -0
 - data/spec/unit/braintree/paged_collection_spec.rb +128 -0
 - data/spec/unit/braintree/ssl_expiration_check_spec.rb +92 -0
 - data/spec/unit/braintree/successful_result_spec.rb +27 -0
 - data/spec/unit/braintree/transaction/credit_card_details_spec.rb +22 -0
 - data/spec/unit/braintree/transaction_spec.rb +136 -0
 - data/spec/unit/braintree/transparent_redirect_spec.rb +154 -0
 - data/spec/unit/braintree/util_spec.rb +142 -0
 - data/spec/unit/braintree/validation_error_collection_spec.rb +128 -0
 - data/spec/unit/braintree/validation_error_spec.rb +19 -0
 - data/spec/unit/braintree/xml/libxml_spec.rb +51 -0
 - data/spec/unit/braintree/xml_spec.rb +122 -0
 - data/spec/unit/spec_helper.rb +1 -0
 - metadata +118 -0
 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Braintree
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Transaction
         
     | 
| 
      
 3 
     | 
    
         
            +
                class AddressDetails # :nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  include BaseModule
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :first_name, :last_name, :company,
         
     | 
| 
      
 7 
     | 
    
         
            +
                    :street_address, :extended_address, :locality, :region,
         
     | 
| 
      
 8 
     | 
    
         
            +
                    :postal_code, :country_name
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(attributes)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    set_instance_variables_from_hash attributes unless attributes.nil?
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Braintree
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Transaction
         
     | 
| 
      
 3 
     | 
    
         
            +
                class CreditCardDetails # :nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  include BaseModule
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :bin, :card_type, :expiration_month,
         
     | 
| 
      
 7 
     | 
    
         
            +
                    :expiration_year, :issuer_location, :last_4, :token
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def initialize(attributes)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    set_instance_variables_from_hash attributes unless attributes.nil?
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  
         
     | 
| 
      
 13 
     | 
    
         
            +
                  def expiration_date
         
     | 
| 
      
 14 
     | 
    
         
            +
                    "#{expiration_month}/#{expiration_year}"
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def masked_number
         
     | 
| 
      
 18 
     | 
    
         
            +
                    "#{bin}******#{last_4}"
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Braintree
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Transaction
         
     | 
| 
      
 3 
     | 
    
         
            +
                class CustomerDetails # :nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  include BaseModule
         
     | 
| 
      
 5 
     | 
    
         
            +
                  
         
     | 
| 
      
 6 
     | 
    
         
            +
                  attr_reader :company, :email, :fax, :first_name, :id, :last_name, :phone, :website
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def initialize(attributes)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    set_instance_variables_from_hash attributes unless attributes.nil?
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,110 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Braintree
         
     | 
| 
      
 2 
     | 
    
         
            +
              # The TransparentRedirect module provides methods to build the tr_data param
         
     | 
| 
      
 3 
     | 
    
         
            +
              # that must be submitted when using the transparent redirect API. For more information
         
     | 
| 
      
 4 
     | 
    
         
            +
              # about transparent redirect, see (TODO).
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # You must provide a redirect_url that the gateway will redirect the user to when the
         
     | 
| 
      
 7 
     | 
    
         
            +
              # action is complete.
         
     | 
| 
      
 8 
     | 
    
         
            +
              #
         
     | 
| 
      
 9 
     | 
    
         
            +
              #   tr_data = Braintree::TransparentRedirect.create_customer_data(
         
     | 
| 
      
 10 
     | 
    
         
            +
              #     :redirect_url => "http://example.com/redirect_back_to_merchant_site
         
     | 
| 
      
 11 
     | 
    
         
            +
              #   )
         
     | 
| 
      
 12 
     | 
    
         
            +
              #
         
     | 
| 
      
 13 
     | 
    
         
            +
              # In addition to the redirect_url, any data that needs to be protected from user tampering
         
     | 
| 
      
 14 
     | 
    
         
            +
              # should be included in the tr_data. For example, to prevent the user from tampering with the transaction
         
     | 
| 
      
 15 
     | 
    
         
            +
              # amount, include the amount in the tr_data.
         
     | 
| 
      
 16 
     | 
    
         
            +
              #
         
     | 
| 
      
 17 
     | 
    
         
            +
              #   tr_data = Braintree::TransparentRedirect.transaction_data(
         
     | 
| 
      
 18 
     | 
    
         
            +
              #     :redirect_url => "http://example.com/complete_transaction",
         
     | 
| 
      
 19 
     | 
    
         
            +
              #     :transaction => {:amount => "100.00"}
         
     | 
| 
      
 20 
     | 
    
         
            +
              #   )
         
     | 
| 
      
 21 
     | 
    
         
            +
              module TransparentRedirect
         
     | 
| 
      
 22 
     | 
    
         
            +
                TransparentRedirectKeys = [:redirect_url] # :nodoc:
         
     | 
| 
      
 23 
     | 
    
         
            +
                CreateCustomerSignature = TransparentRedirectKeys + [{:customer => Customer._create_signature}] # :nodoc:
         
     | 
| 
      
 24 
     | 
    
         
            +
                UpdateCustomerSignature = TransparentRedirectKeys + [:customer_id, {:customer => Customer._update_signature}] # :nodoc:
         
     | 
| 
      
 25 
     | 
    
         
            +
                TransactionSignature = TransparentRedirectKeys + [{:transaction => Transaction._create_signature}] # :nodoc:
         
     | 
| 
      
 26 
     | 
    
         
            +
                CreateCreditCardSignature = TransparentRedirectKeys + [{:credit_card => CreditCard._create_signature}] # :nodoc:
         
     | 
| 
      
 27 
     | 
    
         
            +
                UpdateCreditCardSignature = TransparentRedirectKeys + [:payment_method_token, {:credit_card => CreditCard._update_signature}] # :nodoc:
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                # Returns the tr_data string for creating a credit card.
         
     | 
| 
      
 30 
     | 
    
         
            +
                def self.create_credit_card_data(params)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  Util.verify_keys(CreateCreditCardSignature, params)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  _data(params)
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                # Returns the tr_data string for creating a customer.
         
     | 
| 
      
 36 
     | 
    
         
            +
                def self.create_customer_data(params)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  Util.verify_keys(CreateCustomerSignature, params)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  _data(params)
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                # Returns the tr_data string for creating a transaction.
         
     | 
| 
      
 42 
     | 
    
         
            +
                def self.transaction_data(params)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  Util.verify_keys(TransactionSignature, params)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  transaction_type = params[:transaction] && params[:transaction][:type]
         
     | 
| 
      
 45 
     | 
    
         
            +
                  unless %w[sale credit].include?(transaction_type)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    raise ArgumentError, "expected transaction[type] of sale or credit, was: #{transaction_type.inspect}"
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                  _data(params)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                # Returns the tr_data string for updating a credit card.
         
     | 
| 
      
 52 
     | 
    
         
            +
                # The payment_method_token of the credit card to update is required.
         
     | 
| 
      
 53 
     | 
    
         
            +
                #
         
     | 
| 
      
 54 
     | 
    
         
            +
                #   tr_data = Braintree::TransparentRedirect.update_credit_card_data(
         
     | 
| 
      
 55 
     | 
    
         
            +
                #     :redirect_url => "http://example.com/redirect_here",
         
     | 
| 
      
 56 
     | 
    
         
            +
                #     :payment_method_token => "token123"
         
     | 
| 
      
 57 
     | 
    
         
            +
                #   )
         
     | 
| 
      
 58 
     | 
    
         
            +
                def self.update_credit_card_data(params)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  Util.verify_keys(UpdateCreditCardSignature, params)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  unless params[:payment_method_token]
         
     | 
| 
      
 61 
     | 
    
         
            +
                    raise ArgumentError, "expected params to contain :payment_method_token of payment method to update"
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  _data(params)
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                # Returns the tr_data string for updating a customer.
         
     | 
| 
      
 67 
     | 
    
         
            +
                # The customer_id of the customer to update is required.
         
     | 
| 
      
 68 
     | 
    
         
            +
                #
         
     | 
| 
      
 69 
     | 
    
         
            +
                #   tr_data = Braintree::TransparentRedirect.update_customer_data(
         
     | 
| 
      
 70 
     | 
    
         
            +
                #     :redirect_url => "http://example.com/redirect_here",
         
     | 
| 
      
 71 
     | 
    
         
            +
                #     :customer_id => "customer123"
         
     | 
| 
      
 72 
     | 
    
         
            +
                #   )
         
     | 
| 
      
 73 
     | 
    
         
            +
                def self.update_customer_data(params)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  Util.verify_keys(UpdateCustomerSignature, params)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  unless params[:customer_id]
         
     | 
| 
      
 76 
     | 
    
         
            +
                    raise ArgumentError, "expected params to contain :customer_id of customer to update"
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                  _data(params)
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def self.parse_and_validate_query_string(query_string) # :nodoc:
         
     | 
| 
      
 82 
     | 
    
         
            +
                  params = Util.symbolize_keys(Util.parse_query_string(query_string))
         
     | 
| 
      
 83 
     | 
    
         
            +
                  query_string_without_hash = query_string[/(.*)&hash=.*/, 1]
         
     | 
| 
      
 84 
     | 
    
         
            +
                  if _hash(query_string_without_hash) == params[:hash]
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if params[:http_status] == '200'
         
     | 
| 
      
 86 
     | 
    
         
            +
                      params
         
     | 
| 
      
 87 
     | 
    
         
            +
                    else
         
     | 
| 
      
 88 
     | 
    
         
            +
                      Util.raise_exception_for_status_code(params[:http_status])
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  else
         
     | 
| 
      
 91 
     | 
    
         
            +
                    raise ForgedQueryString
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                def self._data(params) # :nodoc:
         
     | 
| 
      
 96 
     | 
    
         
            +
                  raise ArgumentError, "expected params to contain :redirect_url" unless params[:redirect_url]
         
     | 
| 
      
 97 
     | 
    
         
            +
                  tr_data_segment = Util.hash_to_query_string(params.merge(
         
     | 
| 
      
 98 
     | 
    
         
            +
                    :api_version => Configuration::API_VERSION,
         
     | 
| 
      
 99 
     | 
    
         
            +
                    :time => Time.now.utc.strftime("%Y%m%d%H%M%S"),
         
     | 
| 
      
 100 
     | 
    
         
            +
                    :public_key => Configuration.public_key
         
     | 
| 
      
 101 
     | 
    
         
            +
                  ))
         
     | 
| 
      
 102 
     | 
    
         
            +
                  tr_data_hash = _hash(tr_data_segment)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  "#{tr_data_hash}|#{tr_data_segment}"
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
                
         
     | 
| 
      
 106 
     | 
    
         
            +
                def self._hash(string) # :nodoc:
         
     | 
| 
      
 107 
     | 
    
         
            +
                  ::Braintree::Digest.hexdigest(string)
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
              end
         
     | 
| 
      
 110 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,94 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Braintree
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Util # :nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                def self.extract_attribute_as_array(hash, attribute)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  value = hash.delete(attribute)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  value.is_a?(Array) ? value : [value]
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def self.hash_to_query_string(hash, namespace = nil)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  hash.collect do |key, value|
         
     | 
| 
      
 10 
     | 
    
         
            +
                    full_key = namespace ? "#{namespace}[#{key}]" : key
         
     | 
| 
      
 11 
     | 
    
         
            +
                    if value.is_a?(Hash)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      hash_to_query_string(value, full_key)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    else
         
     | 
| 
      
 14 
     | 
    
         
            +
                      url_encode(full_key) + "=" + url_encode(value)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end.sort * '&'
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
                
         
     | 
| 
      
 19 
     | 
    
         
            +
                def self.parse_query_string(qs)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  qs.split('&').inject({}) do |result, couplet|
         
     | 
| 
      
 21 
     | 
    
         
            +
                    pair = couplet.split('=')
         
     | 
| 
      
 22 
     | 
    
         
            +
                    result[CGI.unescape(pair[0]).to_sym] = CGI.unescape(pair[1])
         
     | 
| 
      
 23 
     | 
    
         
            +
                    result
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
                
         
     | 
| 
      
 27 
     | 
    
         
            +
                def self.url_encode(text)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  CGI.escape text.to_s
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def self.symbolize_keys(hash)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  hash.each do |key, value|
         
     | 
| 
      
 33 
     | 
    
         
            +
                    hash.delete(key)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    hash[key.to_sym] = value
         
     | 
| 
      
 35 
     | 
    
         
            +
                    if value.is_a?(Hash)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      symbolize_keys(value)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    elsif value.is_a?(Array) && value.all? { |v| v.is_a?(Hash) }
         
     | 
| 
      
 38 
     | 
    
         
            +
                      value.each { |v| symbolize_keys(v) }
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end 
         
     | 
| 
      
 41 
     | 
    
         
            +
                  hash
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                def self.raise_exception_for_status_code(status_code)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  case status_code.to_i
         
     | 
| 
      
 46 
     | 
    
         
            +
                  when 401
         
     | 
| 
      
 47 
     | 
    
         
            +
                    raise AuthenticationError
         
     | 
| 
      
 48 
     | 
    
         
            +
                  when 403
         
     | 
| 
      
 49 
     | 
    
         
            +
                    raise AuthorizationError
         
     | 
| 
      
 50 
     | 
    
         
            +
                  when 404
         
     | 
| 
      
 51 
     | 
    
         
            +
                    raise NotFoundError
         
     | 
| 
      
 52 
     | 
    
         
            +
                  when 500
         
     | 
| 
      
 53 
     | 
    
         
            +
                    raise ServerError
         
     | 
| 
      
 54 
     | 
    
         
            +
                  when 503
         
     | 
| 
      
 55 
     | 
    
         
            +
                    raise DownForMaintenanceError
         
     | 
| 
      
 56 
     | 
    
         
            +
                  else
         
     | 
| 
      
 57 
     | 
    
         
            +
                    raise UnexpectedError, "Unexpected HTTP_RESPONSE #{status_code.to_i}"
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
                
         
     | 
| 
      
 61 
     | 
    
         
            +
                def self.verify_keys(valid_keys, hash)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  invalid_keys = _flatten_hash_keys(hash) - _flatten_valid_keys(valid_keys)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  if invalid_keys.any?
         
     | 
| 
      
 64 
     | 
    
         
            +
                    sorted = invalid_keys.sort_by { |k| k.to_s }.join(", ")
         
     | 
| 
      
 65 
     | 
    
         
            +
                    raise ArgumentError, "invalid keys: #{sorted}"
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
                
         
     | 
| 
      
 69 
     | 
    
         
            +
                def self._flatten_valid_keys(valid_keys, namespace = nil)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  valid_keys.inject([]) do |result, key|
         
     | 
| 
      
 71 
     | 
    
         
            +
                    if key.is_a?(Hash)
         
     | 
| 
      
 72 
     | 
    
         
            +
                      full_key = key.keys[0]
         
     | 
| 
      
 73 
     | 
    
         
            +
                      full_key = (namespace ? "#{namespace}[#{full_key}]" : full_key)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      result += _flatten_valid_keys(key.values[0], full_key)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    else
         
     | 
| 
      
 76 
     | 
    
         
            +
                      result << (namespace ? "#{namespace}[#{key}]" : key.to_s)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    end
         
     | 
| 
      
 78 
     | 
    
         
            +
                    result
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end.sort
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
                
         
     | 
| 
      
 82 
     | 
    
         
            +
                def self._flatten_hash_keys(hash, namespace = nil)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  hash.inject([]) do |result, (key, value)|
         
     | 
| 
      
 84 
     | 
    
         
            +
                    full_key = (namespace ? "#{namespace}[#{key}]" : key.to_s)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    if value.is_a?(Hash)
         
     | 
| 
      
 86 
     | 
    
         
            +
                      result += _flatten_hash_keys(value, full_key)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    else
         
     | 
| 
      
 88 
     | 
    
         
            +
                      result << full_key
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                    result
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end.sort
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
              end
         
     | 
| 
      
 94 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,15 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Braintree
         
     | 
| 
      
 2 
     | 
    
         
            +
              class ValidationError
         
     | 
| 
      
 3 
     | 
    
         
            +
                include BaseModule
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :attribute, :code, :message
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(attributes)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  set_instance_variables_from_hash attributes
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
                
         
     | 
| 
      
 11 
     | 
    
         
            +
                def inspect # :nodoc:
         
     | 
| 
      
 12 
     | 
    
         
            +
                  "#<#{self.class} (#{code}) #{message}>"
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,80 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Braintree
         
     | 
| 
      
 2 
     | 
    
         
            +
              # A collection of validation errors.
         
     | 
| 
      
 3 
     | 
    
         
            +
              #
         
     | 
| 
      
 4 
     | 
    
         
            +
              #   result = Braintree::Customer.create(
         
     | 
| 
      
 5 
     | 
    
         
            +
              #     :email => "invalid",
         
     | 
| 
      
 6 
     | 
    
         
            +
              #     :credit_card => {
         
     | 
| 
      
 7 
     | 
    
         
            +
              #       :number => "invalidnumber",
         
     | 
| 
      
 8 
     | 
    
         
            +
              #       :billing_address => {
         
     | 
| 
      
 9 
     | 
    
         
            +
              #         :country_name => "invalid"
         
     | 
| 
      
 10 
     | 
    
         
            +
              #       }
         
     | 
| 
      
 11 
     | 
    
         
            +
              #     }
         
     | 
| 
      
 12 
     | 
    
         
            +
              #   )
         
     | 
| 
      
 13 
     | 
    
         
            +
              #   result.success?
         
     | 
| 
      
 14 
     | 
    
         
            +
              #   #=> false
         
     | 
| 
      
 15 
     | 
    
         
            +
              #   result.errors.for(:customer).on(:email)
         
     | 
| 
      
 16 
     | 
    
         
            +
              #   #=> [#<Braintree::ValidationError (81604) Email is an invalid format.>]
         
     | 
| 
      
 17 
     | 
    
         
            +
              #   result.errors.for(:customer).for(:credit_card).on(:number)
         
     | 
| 
      
 18 
     | 
    
         
            +
              #   #=> [#<Braintree::ValidationError (81715) Credit card number is invalid.>]
         
     | 
| 
      
 19 
     | 
    
         
            +
              #   result.errors.for(:customer).for(:credit_card).for(:billing_address).on(:country_name)
         
     | 
| 
      
 20 
     | 
    
         
            +
              #   #=> [#<Braintree::ValidationError (91803) Country name is not an accepted country.>]
         
     | 
| 
      
 21 
     | 
    
         
            +
              class ValidationErrorCollection
         
     | 
| 
      
 22 
     | 
    
         
            +
                include Enumerable
         
     | 
| 
      
 23 
     | 
    
         
            +
              
         
     | 
| 
      
 24 
     | 
    
         
            +
                def initialize(data) # :nodoc:
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @errors = data[:errors].map { |hash| Braintree::ValidationError.new(hash) }
         
     | 
| 
      
 26 
     | 
    
         
            +
                  @nested = {}
         
     | 
| 
      
 27 
     | 
    
         
            +
                  data.keys.each do |key|
         
     | 
| 
      
 28 
     | 
    
         
            +
                    next if key == :errors
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @nested[key] = ValidationErrorCollection.new(data[key])
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
                
         
     | 
| 
      
 33 
     | 
    
         
            +
                # Accesses the error at the given index.
         
     | 
| 
      
 34 
     | 
    
         
            +
                def [](index)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @errors[index]
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def deep_size # :nodoc:
         
     | 
| 
      
 39 
     | 
    
         
            +
                  size + @nested.values.inject(0) { |count, error_collection| count + error_collection.deep_size }
         
     | 
| 
      
 40 
     | 
    
         
            +
                end
         
     | 
| 
      
 41 
     | 
    
         
            +
              
         
     | 
| 
      
 42 
     | 
    
         
            +
                # Iterates over errors at the current level. Nested errors will not be yielded.
         
     | 
| 
      
 43 
     | 
    
         
            +
                def each(&block)
         
     | 
| 
      
 44 
     | 
    
         
            +
                  @errors.each(&block)
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                # Returns a ValidationErrorCollection of errors nested under the given nested_key.
         
     | 
| 
      
 48 
     | 
    
         
            +
                # Returns nil if there are not any errors nested under the given key.
         
     | 
| 
      
 49 
     | 
    
         
            +
                def for(nested_key)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @nested[nested_key]
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def inspect # :nodoc:
         
     | 
| 
      
 54 
     | 
    
         
            +
                  "#<#{self.class} errors#{_inner_inspect}>"
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                # Returns an array of ValidationError objects on the given attribute.
         
     | 
| 
      
 58 
     | 
    
         
            +
                def on(attribute)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  @errors.select { |error| error.attribute == attribute.to_s }
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
              
         
     | 
| 
      
 62 
     | 
    
         
            +
                # The number of errors at this level. This does not include nested errors.
         
     | 
| 
      
 63 
     | 
    
         
            +
                def size
         
     | 
| 
      
 64 
     | 
    
         
            +
                  @errors.size
         
     | 
| 
      
 65 
     | 
    
         
            +
                end  
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def _inner_inspect(scope = []) # :nodoc:
         
     | 
| 
      
 68 
     | 
    
         
            +
                  all = []
         
     | 
| 
      
 69 
     | 
    
         
            +
                  scope_string = scope.join("/")
         
     | 
| 
      
 70 
     | 
    
         
            +
                  if @errors.any?
         
     | 
| 
      
 71 
     | 
    
         
            +
                    all << "#{scope_string}:[" + @errors.map { |e| "(#{e.code}) #{e.message}" }.join(", ") + "]"
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @nested.each do |key, values|
         
     | 
| 
      
 74 
     | 
    
         
            +
                    all << values._inner_inspect(scope + [key])
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
                  all.join(", ")
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
              end  
         
     | 
| 
      
 79 
     | 
    
         
            +
            end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,80 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Portions of this code were copied and modified from Ruby on Rails, released
         
     | 
| 
      
 2 
     | 
    
         
            +
            # under the MIT license, copyright (c) 2005-2009 David Heinemeier Hansson
         
     | 
| 
      
 3 
     | 
    
         
            +
            module Braintree
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Xml
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Generator # :nodoc:
         
     | 
| 
      
 6 
     | 
    
         
            +
                  XML_TYPE_NAMES = {
         
     | 
| 
      
 7 
     | 
    
         
            +
                    "Fixnum"     => "integer",
         
     | 
| 
      
 8 
     | 
    
         
            +
                    "Bignum"     => "integer",
         
     | 
| 
      
 9 
     | 
    
         
            +
                    "TrueClass"  => "boolean",
         
     | 
| 
      
 10 
     | 
    
         
            +
                    "FalseClass" => "boolean",
         
     | 
| 
      
 11 
     | 
    
         
            +
                    "DateTime"   => "datetime",
         
     | 
| 
      
 12 
     | 
    
         
            +
                    "Time"       => "datetime",
         
     | 
| 
      
 13 
     | 
    
         
            +
                  }
         
     | 
| 
      
 14 
     | 
    
         
            +
                  XML_FORMATTING = {
         
     | 
| 
      
 15 
     | 
    
         
            +
                    "symbol"   => Proc.new { |symbol| symbol.to_s },
         
     | 
| 
      
 16 
     | 
    
         
            +
                    "datetime" => Proc.new { |time| time.xmlschema },
         
     | 
| 
      
 17 
     | 
    
         
            +
                  }
         
     | 
| 
      
 18 
     | 
    
         
            +
                  
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def self.hash_to_xml(hash)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    root, contents = hash.keys[0], hash.values[0]
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    if contents.is_a?(String)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      builder = Builder::XmlMarkup.new
         
     | 
| 
      
 24 
     | 
    
         
            +
                      builder.__send__(root) { |b| b.text! contents }
         
     | 
| 
      
 25 
     | 
    
         
            +
                    else
         
     | 
| 
      
 26 
     | 
    
         
            +
                      _convert_to_xml contents, :root => root
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  def self._convert_to_xml(hash_to_convert, options = {})
         
     | 
| 
      
 31 
     | 
    
         
            +
                    raise ArgumentError, "need root" unless options[:root]
         
     | 
| 
      
 32 
     | 
    
         
            +
                    options[:indent] ||= 2
         
     | 
| 
      
 33 
     | 
    
         
            +
                    options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
         
     | 
| 
      
 34 
     | 
    
         
            +
                    options[:builder].instruct! unless options.delete(:skip_instruct)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    root = options[:root].to_s.tr("_", "-")
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    options[:builder].__send__(:method_missing, root) do
         
     | 
| 
      
 38 
     | 
    
         
            +
                      hash_to_convert.each do |key, value|
         
     | 
| 
      
 39 
     | 
    
         
            +
                        case value
         
     | 
| 
      
 40 
     | 
    
         
            +
                        when ::Hash
         
     | 
| 
      
 41 
     | 
    
         
            +
                          _convert_to_xml(value, options.merge(:root => key, :skip_instruct => true))
         
     | 
| 
      
 42 
     | 
    
         
            +
                        when ::Array
         
     | 
| 
      
 43 
     | 
    
         
            +
                          _array_to_xml(value, options.merge(:root => key, :skip_instruct => true))
         
     | 
| 
      
 44 
     | 
    
         
            +
                        else
         
     | 
| 
      
 45 
     | 
    
         
            +
                          type_name = XML_TYPE_NAMES[value.class.name]
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                          key = key.to_s.tr("_", "-")
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                          attributes = ((value.nil? || type_name.nil?) ? {} : { :type => type_name })
         
     | 
| 
      
 50 
     | 
    
         
            +
                          if value.nil?
         
     | 
| 
      
 51 
     | 
    
         
            +
                            attributes[:nil] = true
         
     | 
| 
      
 52 
     | 
    
         
            +
                          end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                          options[:builder].tag!(key,
         
     | 
| 
      
 55 
     | 
    
         
            +
                            XML_FORMATTING[type_name] ? XML_FORMATTING[type_name].call(value) : value,
         
     | 
| 
      
 56 
     | 
    
         
            +
                            attributes
         
     | 
| 
      
 57 
     | 
    
         
            +
                          )
         
     | 
| 
      
 58 
     | 
    
         
            +
                        end
         
     | 
| 
      
 59 
     | 
    
         
            +
                      end
         
     | 
| 
      
 60 
     | 
    
         
            +
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  
         
     | 
| 
      
 64 
     | 
    
         
            +
                  def self._array_to_xml(array, options = {})
         
     | 
| 
      
 65 
     | 
    
         
            +
                    raise "expected all elements to be hashes" unless array.all? { |e| e.is_a?(Hash) }
         
     | 
| 
      
 66 
     | 
    
         
            +
                    raise "expected options[:root]" unless options[:root]
         
     | 
| 
      
 67 
     | 
    
         
            +
                    raise "expected options[:builder]" unless options[:builder]
         
     | 
| 
      
 68 
     | 
    
         
            +
                    options[:indent] ||= 2
         
     | 
| 
      
 69 
     | 
    
         
            +
                    root = options.delete(:root).to_s.tr("_", "-")
         
     | 
| 
      
 70 
     | 
    
         
            +
                    if array.empty?
         
     | 
| 
      
 71 
     | 
    
         
            +
                      options[:builder].tag!(root, :type => "array")
         
     | 
| 
      
 72 
     | 
    
         
            +
                    else
         
     | 
| 
      
 73 
     | 
    
         
            +
                      options[:builder].tag!(root, :type => "array") do
         
     | 
| 
      
 74 
     | 
    
         
            +
                        array.each { |e| _convert_to_xml(e, options.merge(:root => "item", :skip_instruct => true)) }
         
     | 
| 
      
 75 
     | 
    
         
            +
                      end
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
            end
         
     |