Class: Rack::Payment::Request

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/rack-payment/request.rb

Overview

When you call #call, a new Request instance gets created and it does the actual logic to figure out what to do.

The #finish method “executes” this class (it figures out what to do).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env, payment_instance) ⇒ Request

Instantiates a Rack::Payment::Request object which basically wraps a single request and handles all of the logic to determine what to do.

Calling #finish will return the actual Rack response

Parameters:

  • The (Hash)

    Rack Request environment variables

  • The (Rack::Payment)

    instance of Rack::Payment handling this request



81
82
83
84
85
86
87
88
89
# File 'lib/rack-payment/request.rb', line 81

def initialize env, payment_instance
  @payment_instance = payment_instance

  self.env          = env
  self.request      = Rack::Request.new @env

  raw_rack_response = app.call env
  self.app_response = Rack::Response.new raw_rack_response[2], raw_rack_response[0], raw_rack_response[1]
end

Instance Attribute Details

#app_responseObject

Rack::Response that results from calling the actual Rack application.

Rack::Response


39
40
41
# File 'lib/rack-payment/request.rb', line 39

def app_response
  @app_response
end

#envHash

Returns Raw Rack env Hash.

Returns:

  • (Hash)

    Raw Rack env Hash



30
31
32
# File 'lib/rack-payment/request.rb', line 30

def env
  @env
end

#payment_instanceRack::Payment

The instance of Rack::Payment that this Request is for

Returns:



51
52
53
# File 'lib/rack-payment/request.rb', line 51

def payment_instance
  @payment_instance
end

#post_came_from_the_built_in_formstrue, false

Whether or not this request’s POST came from our built in forms.

* If true, we think the POST came from our form.
* If false, we think the POST came from a user's custom form.

Returns:

  • (true, false)


47
48
49
# File 'lib/rack-payment/request.rb', line 47

def post_came_from_the_built_in_forms
  @post_came_from_the_built_in_forms
end

#requestObject

An instance of Rack::Request that wraps our #env. It makes it much easier to access the params, path, method, etc.

Returns:

  • Rack::Request



35
36
37
# File 'lib/rack-payment/request.rb', line 35

def request
  @request
end

Instance Method Details

#amount_in_sessionObject



66
67
68
# File 'lib/rack-payment/request.rb', line 66

def amount_in_session
  session[:amount]
end

#amount_in_session=(value) ⇒ Object



70
71
72
# File 'lib/rack-payment/request.rb', line 70

def amount_in_session= value
  session[:amount] = value
end

#credit_card_and_billing_info_responseObject



215
216
217
218
219
220
221
222
223
# File 'lib/rack-payment/request.rb', line 215

def credit_card_and_billing_info_response
  css_file  = ::File.dirname(__FILE__) + '/views/credit-card-and-billing-info-form.css'
  form_html = payment.form :post_to => built_in_form_path, :inline_css => ::File.read(css_file)
  layout    = ::File.dirname(__FILE__) + '/views/layout.html'
  html      = ::File.read(layout)
  html      = html.sub 'CONTENT', form_html

  [ 200, {'Content-Type' => 'text/html'}, [html] ]
end

#express_cancel_urlObject



25
26
27
# File 'lib/rack-payment/request.rb', line 25

def express_cancel_url
  ::File.join request.url.sub(request.path_info, ''), express_cancel_path
end

#express_ok_urlObject

TODO test these!!!



22
23
24
# File 'lib/rack-payment/request.rb', line 22

def express_ok_url
  ::File.join request.url.sub(request.path_info, ''), express_ok_path
end

#finishArray

Generates and returns the final rack response.

This “runs” the request. It’s the main logic in Rack::Payment!

Returns:

  • (Array)

    A Rack response, eg. ‘[200, {}, [“Hello World”]]`



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/rack-payment/request.rb', line 96

def finish

  # The application returned a 402 ('Payment Required')
  if app_response.status == 402
    self.amount_in_session = payment.amount
    
    return setup_express_purchase if payment.use_express?
    
    if payment.card_or_address_partially_filled_out?
      return process_credit_card
    else
      return credit_card_and_billing_info_response
    end

  # The requested path matches our built-in form
  elsif request.path_info == built_in_form_path
    self.post_came_from_the_built_in_forms = true
    return process_credit_card 

  # The requested path matches our callback for express payments
  elsif request.path_info == express_ok_path
    return process_express_payment_callback
  end

  # If we haven't returned anything, there was no reason for the 
  # middleware to handle this request so we return the real 
  # application's response.
  app_response.finish
end

#paymentObject



57
58
59
# File 'lib/rack-payment/request.rb', line 57

def payment
  env[env_helper_variable] ||= Rack::Payment::Helper.new(payment_instance)
end

#post_came_from_the_built_in_forms?Boolean

Returns:

  • (Boolean)


53
54
55
# File 'lib/rack-payment/request.rb', line 53

def post_came_from_the_built_in_forms?
  post_came_from_the_built_in_forms == true
end

#process_credit_cardObject

Gets parameters, attempts an #authorize call, attempts a #capture call, and renders the results.



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/rack-payment/request.rb', line 128

def process_credit_card
  payment.amount ||= amount_in_session

  # The params *should* be set on the payment data object, but we accept 
  # POST requests too, so we check the POST variables for credit_card 
  # or billing_address fields
  #
  # TODO deprecate this in favor of the more conventional credit_card[number] syntax?
  #
  params.each do |field, value|
    if field =~ /^credit_card_(\w+)/
      payment.credit_card.update $1 => value
    elsif field =~ /billing_address_(\w+)/
      payment.billing_address.update $1 => value
    end 
  end

  # We also accept credit_card[number] style params, which Rack supports
  if params['credit_card'] and params['credit_card'].respond_to?(:each)
    payment.credit_card.update params['credit_card']
  end
  if params['billing_address'] and params['billing_address'].respond_to?(:each)
    payment.billing_address.update params['billing_address']
  end

  # Purchase!
  if payment.purchase(:ip => request.ip)
    render_on_success
  else
    render_on_error payment.errors
  end
end

#process_express_payment_callbackObject



225
226
227
228
229
230
231
232
233
234
235
# File 'lib/rack-payment/request.rb', line 225

def process_express_payment_callback
  payment.amount ||= amount_in_session # gets lost because we're coming here directly from PayPal

  details = express_gateway.details_for params['token']

  payment.raw_express_response = express_gateway.purchase payment.amount_in_cents, :ip       => request.ip,
                                                                                   :token    => params['token'],
                                                                                   :payer_id => details.payer_id

  render_on_success
end

#render_on_error(errors) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/rack-payment/request.rb', line 177

def render_on_error errors
  if post_came_from_the_built_in_forms?
    # we POSTed from our form, so let's re-render our form
    credit_card_and_billing_info_response
  else
    # pass along the errors to the application's custom page, which should be the current URL
    # so we can actually just re-call the same env (should display the form) using a GET
    payment.errors = errors
    new_env = env.clone
    new_env['REQUEST_METHOD'] = 'GET'

    # Rails keeps track of its own Request/Response.
    #
    # If we're using Rails, we need to delete these variables 
    # to trick Rails into thinking that this is a new request.
    #
    # Kind of icky!
    new_env.delete 'action_controller.rescue.request'
    new_env.delete 'action_controller.rescue.response'

    new_env['PATH_INFO'] = on_success if request.path_info == express_ok_path # if express, we render on_success
    app.call(new_env)
  end
end

#render_on_successObject



202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/rack-payment/request.rb', line 202

def render_on_success
  if on_success
    # on_success is overriden ... we #call the main application using the on_success path
    new_env = env.clone
    new_env['PATH_INFO']      = on_success
    new_env['REQUEST_METHOD'] = 'GET'
    app.call new_env
  else
    # on_success has not been overriden ... let's just display out own info
    [ 200, {'Content-Type' => 'text/html'}, ["Order successful.  You should have been charged #{ payment.amount }" ]]
  end
end

#sessionObject



61
62
63
64
# File 'lib/rack-payment/request.rb', line 61

def session
  raise "Rack env['#{rack_session_variable}'] is nil.  Has a Rack::Session middleware be enabled?" if env[rack_session_variable].nil?
  env[rack_session_variable][session_variable] ||= {}
end

#setup_express_purchaseObject



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rack-payment/request.rb', line 161

def setup_express_purchase
  # TODO we should get the callback URLs to use from the Rack::Purchase
  #      and they should be overridable

  # TODO go BOOM if the express gateway isn't set!

  # TODO catch exceptions

  # TODO catch ! success?
  response = express_gateway.setup_purchase payment.amount_in_cents, :ip                => request.ip, 
                                                                     :return_url        => express_ok_url,
                                                                     :cancel_return_url => express_cancel_url

  [ 302, {'Location' => express_gateway.redirect_url_for(response.token)}, ['Redirecting to PayPal Express Checkout'] ]
end