#!/usr/bin/env ruby
%w( rubygems mime/types camping xmlsimple
digest/md5 net/https redcloth pp).each { |lib| require lib }
Camping.goes :UtiliTool
module UtiliTool::Models
class Hasher
attr_accessor :variables
def initialize(variables = nil)
self.variables = variables.nil? ? [] : variables
end
def string_to_hash; variables.join("|") end
def hash
self.variables.any? ? Digest::MD5.hexdigest(self.string_to_hash) : ""
end
def hashed?; self.variables.length > 0 ? true : false end
end
class Braintree
attr_accessor :orderid, :amount, :key, :key_id, :time
def initialize(attributes = nil)
unless attributes.nil?
attributes.each { |k,v| self.send("#{k}=", v) } unless attributes.nil?
self.time = self.class.current_time unless attributes.include?(:time)
else
self.time = self.class.current_time
end
end
def self.current_time
Time.now.getutc.strftime("%Y%m%d%H%m%S")
end
end
class GatewayRequest < Braintree
attr_accessor :api, :url_base, :uri_string
attr_reader :url
def initialize(attributes = nil, form_inputs = nil)
attributes.each { |k,v| self.send("#{k}=", v)} unless attributes.nil?
determine_api_url_base
self.uri_string = create_uri_string_from_form_inputs(form_inputs) unless form_inputs.nil?
end
def url
[self.url_base, self.uri_string].join("?")
end
# Sending a request relies on net/https instead of open-uri because
# it's easier to skip the SSL validity checks. In Ruby 1.9, this
# won't be necessary.
def send_request
uri = URI.parse self.url
server = Net::HTTP.new uri.host, uri.port
server.use_ssl = uri.scheme == 'https'
server.verify_mode = OpenSSL::SSL::VERIFY_NONE
# use POST instead of GET
response = server.post self.url_base, self.uri_string
return response.body
end
alias response send_request
private
def determine_api_url_base
if api == "query"
self.url_base = "https://secure.braintreepaymentgateway.com/api/query.php"
else
self.url_base = "https://secure.braintreepaymentgateway.com/api/transact.php"
end
end
# Takes a hash and returns a query string. If there is a field called
# 'quick_query', the key will be dropped, and only the value will be used.
def create_uri_string_from_form_inputs(form_inputs)
uri_array = []
form_inputs.delete_if { |key,value| value.strip == "" }
form_inputs.each do |key, value|
key == 'quick_query' ? uri_array << value : uri_array << "#{key}=#{value}"
end
uri_array.join("&")
end
end
class GatewayResponse < Braintree
attr_accessor :response_body, :format, :formatted_response_body
def initialize(response_body, format = nil)
self.response_body = response_body
self.format = format
self.formatted_response_body = format_response_body
end
def to_hash
if self.format.nil?
response_hash = { }
self.response_body.split("&").each do |pair|
pair_array = pair.split("=")
response_hash[pair_array[0]] = pair_array[1]
end
response_hash.delete_if { |key, value| value.nil? }
else
response_hash = XmlSimple.xml_in(self.response_body, { 'SupressEmpty' => true, 'NormaliseSpace' => 2 })
end
return response_hash
end
private
def format_response_body
unless self.format.nil?
xml_oo = XmlSimple.xml_in(self.response_body, { 'SuppressEmpty' => true })
xml_oo_out = XmlSimple.xml_out(xml_oo, { 'NoEscape' => true })
formatted = xml_oo_out.gsub("<", "<").gsub(">", ">")
return formatted
end
end
end
end
module UtiliTool::Controllers
# class Something < R 'route'
# include Responder
#
# def get
# ... important code ...
#
# respond_to do |format|
# format.html { render :something }
# format.text { "Just some text." }
# format.yaml { "Something neat!".to_yaml }
# format.xml { "Also, XML.".to_xml }
# end
# end
# end
module Responder
def respond_to
yield response = Response.new(env.HTTP_ACCEPT)
@headers['Content-Type'] = response.content_type
response.body
end
class Response
attr_reader :body, :content_type
def initialize(accept) @accept = accept end
TYPES = {
:yaml => %w[application/yaml text/yaml],
:text => %w[text/plain],
:html => %w[text/html */* application/html],
:xml => %w[application/xml]
}
def method_missing(method, *args)
if TYPES[method] && @accept =~ Regexp.union(*TYPES[method])
@content_type = TYPES[method].first
@body = yield if block_given?
end
end
end
end
class Index < R '/'
include Responder
def get
respond_to do |format|
format.html { render :index }
end
end
end
class Hasher < R '/hasher'
include Responder
def get
@gateway = Braintree.new
respond_to do |format|
format.html { render :hasher }
end
end
def post
@gateway = Braintree.new
@hasher = UtiliTool::Models::Hasher.new([input.orderid, input.key,
input.time, input.amount])
respond_to do |format|
format.html { render :hasher }
end
end
end
# This action gives you a text area to input values to. You
# can then post this directly to the gateway.
class QuickGet < R '/quick_get'
include Responder
def get
@gateway_request = GatewayRequest.new({ :api => "payment" })
respond_to do |format|
format.html { render :quick_get }
end
end
def post
@gateway_request = GatewayRequest.new({ :api => "payment" }, input)
@gateway_response = GatewayResponse.new(@gateway_request.response)
respond_to do |format|
format.html { render :quick_get }
end
end
end
class QuickQuery < R '/quick_query'
include Responder
def get
@gateway_request = GatewayRequest.new({ :api => "query" })
respond_to do |format|
format.html { render :quick_query }
end
end
def post
@gateway_request = GatewayRequest.new( { :api, "query"}, input )
@gateway_response = GatewayResponse.new(@gateway_request.response, "xml")
respond_to do |format|
format.html { render :quick_query }
end
end
end
class Assets < R('/static/(.+)')
PATH = File.expand_path("#{File.dirname(__FILE__)}")
def get file
if file.include? '..'
@status = '403'; return '403 - Invalid path'
else
type = (MIME::Types.type_for(file)[0] || '/text/plain').to_s
@headers['Content-Type'] = type
@headers['X-Sendfile'] = File.join PATH, 'static', file
end
end
end
end
module UtiliTool::Helpers
def site_title; "Braintree Util-i-Tool" end
def split_string(string); string.split("&").join("&\n"); end
def static_content(file)
path = File.expand_path("#{File.dirname(__FILE__)}")
file_path = File.join path, 'contents', "#{file}.textile"
RedCloth.new(File.read(file_path)).to_html
end
def word_wrap(text, line_width = 80)
text.split("&").collect do |line|
line.length > line_width ? line.gsub(/(.{1,#{line_width}})(\s+|$)/, "\\1\n").strip : line
end * "\n"
end
end
module UtiliTool::Views
Camping::Mab.set(:indent, 2)
# Layout
def layout
xhtml_transitional do
head do
title site_title
link(:rel => 'stylesheet', :type => 'text/css',
:href => R(Assets, 'utili_tool.css'), :media => 'screen')
# script(:src => R(Assets, 'jquery-1.2.3.js'), :type => 'text/javascript')
# script(:src => R(Assets, 'utili-tool.js', :type => 'text/javascript'))
end
body do
div.wrapper! do
div.masthead! do
h1 site_title
end
div.container! do
div.sidebar! do
_sidebar
end
div.content! do
self << yield
end
end
div.footer! do
[["Braintree Payment Solutions", "http://www.getbraintree.com"],
["Braintree Developer Community", "http://developer.getbraintree.com"],
["Braintree Merchant Login", "https://secure.braintreepaymentgateway.com/merchants/login.php"],
].map do |txt, link, title|
a txt, :href => link, :title => txt
end.join(" | ")
end
end
_google_analytics
end
end
end
# Partials
def _sidebar
h3 "Tools"
_navigation
end
def _navigation
ul.navigation do
li { a "Home", :href => R(Index), :title => "Home",
:accesskey => "H" }
li { a "Hasher", :href => R(Hasher), :title => "Hasher",
:accesskey => "M" }
li { a "QuickGet", :href => R(QuickGet), :title => "QuickGet",
:accesskey => "G"}
li { a "QuickQuery", :href => R(QuickQuery), :title => "QuickQuery",
:accesskey => "Q"}
end
end
def _google_analytics
script(:type => "text/javascript") do
%[var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));]
end
script(:type => "text/javascript") do
%[var pageTracker = _gat._getTracker("UA-1885256-7");
pageTracker._initData();
pageTracker._trackPageview();]
end
end
# Actions
def index
div.static do; static_content("index"); end
end
def hasher
h2 "Braintree MD5 Hash Generator"
div.static do; static_content("hasher"); end
if @hasher
div.response do
table.response do
tr do
td "The string to hash was:"
td { code @hasher.string_to_hash}
end
tr do
td "The MD5 hash generated was:"
td { code @hasher.hash }
end
end
end
end
form({ :method => 'post', :action => R(Hasher)}) do
fieldset do
legend "Input Values to Hash"
p { label 'Order Id', :for => 'orderid'; br;
input :type => 'text', :name => "orderid" }
p { label 'Amount', :for => 'amount'; br;
input :type => 'text', :name => "amount" }
p { label 'Time', :for => 'time'; br;
input :type => 'text', :name => "time",
:value => @gateway.time }
p { label 'Key', :for => 'key'; br;
input :type => 'text', :name => "key" }
input :type => 'submit', :value => 'Submit'
end
end
end
def quick_get
h2 "QuickGet"
div.static do; static_content("quick_get"); end
unless @gateway_response.nil?
div.response do
h3 "Gateway Response"
p { code { word_wrap(@gateway_request.uri_string) }}
table.response(:cellspacing => "0") do
tr.header do
th "Param"
th "Value"
end
@gateway_response.to_hash.each do |key, value|
tr do
td key
td { code value }
end
end
end
end
end
form({ :method => 'post', :action => R(QuickGet)}) do
fieldset do
legend "Input a query string"
p { label 'Username', :for => 'username'; br;
input :type => 'text', :name => "username" }
p { label 'Password', :for => 'password'; br;
input :type => 'text', :name => "password" }
p { label 'Query', :for => 'quick_query'; br;
textarea :name => "quick_query", :rows => 5, :cols => 55 }
input :type => 'submit', :value => 'Submit'
end
end
end
def quick_query
h2 "QuickQuery"
div.static do; static_content("quick_query"); end
unless @gateway_response.nil?
div.response do
h3 "Raw Gateway Response"
p "Better formatting is on it's way."
p { code { word_wrap(@gateway_request.uri_string) }}
code do
@gateway_response.formatted_response_body
end
end
end
form({ :method => 'post', :action => R(QuickQuery)}) do
fieldset do
legend "Input a query string"
p { label 'Username', :for => 'username'; br;
input :type => 'text', :name => "username" }
p { label 'Password', :for => 'password'; br;
input :type => 'text', :name => "password" }
p { label 'Query', :for => 'quick_query'; br;
textarea :name => "quick_query", :rows => 5, :cols => 55 }
input :type => 'submit', :value => 'Submit'
end
end
end
end
def UtiliTool.create; end