paypal_permissions 0.0.3.3 → 0.0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/README.md +7 -15
  2. data/{examples → examples.old}/app/controllers/paypal_perms_controller.rb +0 -0
  3. data/{examples → examples.old}/app/models/paypal_perm.rb +0 -0
  4. data/{examples → examples.old}/db/migrate/paypal_permissions_create_paypal_perms.rb +0 -0
  5. data/examples/.gitignore +15 -0
  6. data/examples/Gemfile +12 -0
  7. data/examples/README.rdoc +261 -0
  8. data/examples/Rakefile +7 -0
  9. data/examples/app/assets/images/rails.png +0 -0
  10. data/examples/app/assets/javascripts/application.js +15 -0
  11. data/examples/app/assets/javascripts/merchants.js.coffee +3 -0
  12. data/examples/app/assets/stylesheets/application.css +13 -0
  13. data/examples/app/assets/stylesheets/merchants.css.scss +3 -0
  14. data/examples/app/controllers/application_controller.rb +3 -0
  15. data/examples/app/controllers/merchants_controller.rb +61 -0
  16. data/examples/app/controllers/ppp_models_controller.rb +5 -0
  17. data/examples/app/helpers/application_helper.rb +2 -0
  18. data/examples/app/helpers/merchants_helper.rb +2 -0
  19. data/examples/app/mailers/.gitkeep +0 -0
  20. data/examples/app/models/.gitkeep +0 -0
  21. data/examples/app/models/merchant.rb +3 -0
  22. data/examples/app/views/layouts/application.html.erb +14 -0
  23. data/examples/app/views/merchants/show.html.erb +20 -0
  24. data/examples/config.ru +4 -0
  25. data/examples/config/application.rb +59 -0
  26. data/examples/config/boot.rb +6 -0
  27. data/examples/config/database.yml +25 -0
  28. data/examples/config/environment.rb +5 -0
  29. data/examples/config/environments/development.rb +50 -0
  30. data/examples/config/environments/production.rb +79 -0
  31. data/examples/config/environments/test.rb +49 -0
  32. data/examples/config/initializers/backtrace_silencers.rb +7 -0
  33. data/examples/config/initializers/inflections.rb +15 -0
  34. data/examples/config/initializers/mime_types.rb +5 -0
  35. data/examples/config/initializers/secret_token.rb +7 -0
  36. data/examples/config/initializers/session_store.rb +8 -0
  37. data/examples/config/initializers/wrap_parameters.rb +14 -0
  38. data/examples/config/locales/en.yml +5 -0
  39. data/examples/config/routes.rb +4 -0
  40. data/examples/db/migrate/20120415205138_paypal_permissions_create_merchants.rb +13 -0
  41. data/examples/db/seeds.rb +7 -0
  42. data/examples/doc/README_FOR_APP +2 -0
  43. data/examples/lib/assets/.gitkeep +0 -0
  44. data/examples/lib/tasks/.gitkeep +0 -0
  45. data/examples/log/.gitkeep +0 -0
  46. data/examples/public/404.html +26 -0
  47. data/examples/public/422.html +26 -0
  48. data/examples/public/500.html +25 -0
  49. data/examples/public/favicon.ico +0 -0
  50. data/examples/public/index.html +241 -0
  51. data/examples/public/robots.txt +5 -0
  52. data/examples/script/rails +6 -0
  53. data/examples/test/fixtures/.gitkeep +0 -0
  54. data/examples/test/fixtures/merchants.yml +11 -0
  55. data/examples/test/functional/.gitkeep +0 -0
  56. data/examples/test/functional/merchants_controller_test.rb +7 -0
  57. data/examples/test/integration/.gitkeep +0 -0
  58. data/examples/test/performance/browsing_test.rb +12 -0
  59. data/examples/test/test_helper.rb +13 -0
  60. data/examples/test/unit/.gitkeep +0 -0
  61. data/examples/test/unit/helpers/merchants_helper_test.rb +4 -0
  62. data/examples/test/unit/merchant_test.rb +7 -0
  63. data/examples/vendor/assets/javascripts/.gitkeep +0 -0
  64. data/examples/vendor/assets/stylesheets/.gitkeep +0 -0
  65. data/examples/vendor/plugins/.gitkeep +0 -0
  66. data/lib/active_merchant/billing/gateways/paypal_permissions.rb +211 -80
  67. data/lib/active_merchant/billing/gateways/paypal_permissions/x_pp_authorization.rb +41 -0
  68. data/lib/generators/active_record/paypal_permissions_generator.rb +3 -34
  69. data/lib/generators/paypal_permissions/install_generator.rb +6 -2
  70. data/lib/generators/paypal_permissions/orm_helpers.rb +0 -1
  71. data/lib/generators/paypal_permissions/paypal_permissions_generator.rb +4 -1
  72. data/lib/paypal_permissions.rb +0 -4
  73. data/lib/paypal_permissions/version.rb +1 -1
  74. data/paypal_permissions.gemspec +1 -1
  75. metadata +83 -21
@@ -0,0 +1,7 @@
1
+ # This file should contain all the record creation needed to seed the database with its default values.
2
+ # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup).
3
+ #
4
+ # Examples:
5
+ #
6
+ # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }])
7
+ # Mayor.create(name: 'Emanuel', city: cities.first)
@@ -0,0 +1,2 @@
1
+ Use this README file to introduce your application and point to useful places in the API for learning more.
2
+ Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries.
File without changes
File without changes
File without changes
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/404.html -->
21
+ <div class="dialog">
22
+ <h1>The page you were looking for doesn't exist.</h1>
23
+ <p>You may have mistyped the address or the page may have moved.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ </div>
24
+ </body>
25
+ </html>
File without changes
@@ -0,0 +1,241 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Ruby on Rails: Welcome aboard</title>
5
+ <style type="text/css" media="screen">
6
+ body {
7
+ margin: 0;
8
+ margin-bottom: 25px;
9
+ padding: 0;
10
+ background-color: #f0f0f0;
11
+ font-family: "Lucida Grande", "Bitstream Vera Sans", "Verdana";
12
+ font-size: 13px;
13
+ color: #333;
14
+ }
15
+
16
+ h1 {
17
+ font-size: 28px;
18
+ color: #000;
19
+ }
20
+
21
+ a {color: #03c}
22
+ a:hover {
23
+ background-color: #03c;
24
+ color: white;
25
+ text-decoration: none;
26
+ }
27
+
28
+
29
+ #page {
30
+ background-color: #f0f0f0;
31
+ width: 750px;
32
+ margin: 0;
33
+ margin-left: auto;
34
+ margin-right: auto;
35
+ }
36
+
37
+ #content {
38
+ float: left;
39
+ background-color: white;
40
+ border: 3px solid #aaa;
41
+ border-top: none;
42
+ padding: 25px;
43
+ width: 500px;
44
+ }
45
+
46
+ #sidebar {
47
+ float: right;
48
+ width: 175px;
49
+ }
50
+
51
+ #footer {
52
+ clear: both;
53
+ }
54
+
55
+ #header, #about, #getting-started {
56
+ padding-left: 75px;
57
+ padding-right: 30px;
58
+ }
59
+
60
+
61
+ #header {
62
+ background-image: url("assets/rails.png");
63
+ background-repeat: no-repeat;
64
+ background-position: top left;
65
+ height: 64px;
66
+ }
67
+ #header h1, #header h2 {margin: 0}
68
+ #header h2 {
69
+ color: #888;
70
+ font-weight: normal;
71
+ font-size: 16px;
72
+ }
73
+
74
+
75
+ #about h3 {
76
+ margin: 0;
77
+ margin-bottom: 10px;
78
+ font-size: 14px;
79
+ }
80
+
81
+ #about-content {
82
+ background-color: #ffd;
83
+ border: 1px solid #fc0;
84
+ margin-left: -55px;
85
+ margin-right: -10px;
86
+ }
87
+ #about-content table {
88
+ margin-top: 10px;
89
+ margin-bottom: 10px;
90
+ font-size: 11px;
91
+ border-collapse: collapse;
92
+ }
93
+ #about-content td {
94
+ padding: 10px;
95
+ padding-top: 3px;
96
+ padding-bottom: 3px;
97
+ }
98
+ #about-content td.name {color: #555}
99
+ #about-content td.value {color: #000}
100
+
101
+ #about-content ul {
102
+ padding: 0;
103
+ list-style-type: none;
104
+ }
105
+
106
+ #about-content.failure {
107
+ background-color: #fcc;
108
+ border: 1px solid #f00;
109
+ }
110
+ #about-content.failure p {
111
+ margin: 0;
112
+ padding: 10px;
113
+ }
114
+
115
+
116
+ #getting-started {
117
+ border-top: 1px solid #ccc;
118
+ margin-top: 25px;
119
+ padding-top: 15px;
120
+ }
121
+ #getting-started h1 {
122
+ margin: 0;
123
+ font-size: 20px;
124
+ }
125
+ #getting-started h2 {
126
+ margin: 0;
127
+ font-size: 14px;
128
+ font-weight: normal;
129
+ color: #333;
130
+ margin-bottom: 25px;
131
+ }
132
+ #getting-started ol {
133
+ margin-left: 0;
134
+ padding-left: 0;
135
+ }
136
+ #getting-started li {
137
+ font-size: 18px;
138
+ color: #888;
139
+ margin-bottom: 25px;
140
+ }
141
+ #getting-started li h2 {
142
+ margin: 0;
143
+ font-weight: normal;
144
+ font-size: 18px;
145
+ color: #333;
146
+ }
147
+ #getting-started li p {
148
+ color: #555;
149
+ font-size: 13px;
150
+ }
151
+
152
+
153
+ #sidebar ul {
154
+ margin-left: 0;
155
+ padding-left: 0;
156
+ }
157
+ #sidebar ul h3 {
158
+ margin-top: 25px;
159
+ font-size: 16px;
160
+ padding-bottom: 10px;
161
+ border-bottom: 1px solid #ccc;
162
+ }
163
+ #sidebar li {
164
+ list-style-type: none;
165
+ }
166
+ #sidebar ul.links li {
167
+ margin-bottom: 5px;
168
+ }
169
+
170
+ .filename {
171
+ font-style: italic;
172
+ }
173
+ </style>
174
+ <script type="text/javascript">
175
+ function about() {
176
+ info = document.getElementById('about-content');
177
+ if (window.XMLHttpRequest)
178
+ { xhr = new XMLHttpRequest(); }
179
+ else
180
+ { xhr = new ActiveXObject("Microsoft.XMLHTTP"); }
181
+ xhr.open("GET","rails/info/properties",false);
182
+ xhr.send("");
183
+ info.innerHTML = xhr.responseText;
184
+ info.style.display = 'block'
185
+ }
186
+ </script>
187
+ </head>
188
+ <body>
189
+ <div id="page">
190
+ <div id="sidebar">
191
+ <ul id="sidebar-items">
192
+ <li>
193
+ <h3>Browse the documentation</h3>
194
+ <ul class="links">
195
+ <li><a href="http://guides.rubyonrails.org/">Rails Guides</a></li>
196
+ <li><a href="http://api.rubyonrails.org/">Rails API</a></li>
197
+ <li><a href="http://www.ruby-doc.org/core/">Ruby core</a></li>
198
+ <li><a href="http://www.ruby-doc.org/stdlib/">Ruby standard library</a></li>
199
+ </ul>
200
+ </li>
201
+ </ul>
202
+ </div>
203
+
204
+ <div id="content">
205
+ <div id="header">
206
+ <h1>Welcome aboard</h1>
207
+ <h2>You&rsquo;re riding Ruby on Rails!</h2>
208
+ </div>
209
+
210
+ <div id="about">
211
+ <h3><a href="rails/info/properties" onclick="about(); return false">About your application&rsquo;s environment</a></h3>
212
+ <div id="about-content" style="display: none"></div>
213
+ </div>
214
+
215
+ <div id="getting-started">
216
+ <h1>Getting started</h1>
217
+ <h2>Here&rsquo;s how to get rolling:</h2>
218
+
219
+ <ol>
220
+ <li>
221
+ <h2>Use <code>rails generate</code> to create your models and controllers</h2>
222
+ <p>To see all available options, run it without parameters.</p>
223
+ </li>
224
+
225
+ <li>
226
+ <h2>Set up a default route and remove <span class="filename">public/index.html</span></h2>
227
+ <p>Routes are set up in <span class="filename">config/routes.rb</span>.</p>
228
+ </li>
229
+
230
+ <li>
231
+ <h2>Create your database</h2>
232
+ <p>Run <code>rake db:create</code> to create your database. If you're not using SQLite (the default), edit <span class="filename">config/database.yml</span> with your username and password.</p>
233
+ </li>
234
+ </ol>
235
+ </div>
236
+ </div>
237
+
238
+ <div id="footer">&nbsp;</div>
239
+ </div>
240
+ </body>
241
+ </html>
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-Agent: *
5
+ # Disallow: /
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
File without changes
@@ -0,0 +1,11 @@
1
+ # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
2
+
3
+ # This model initially had no columns defined. If you add columns to the
4
+ # model remove the '{}' from the fixture names and add the columns immediately
5
+ # below each fixture, per the syntax in the comments below
6
+ #
7
+ one: {}
8
+ # column: value
9
+ #
10
+ two: {}
11
+ # column: value
File without changes
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class MerchantsControllerTest < ActionController::TestCase
4
+ # test "the truth" do
5
+ # assert true
6
+ # end
7
+ end
File without changes
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+ require 'rails/performance_test_help'
3
+
4
+ class BrowsingTest < ActionDispatch::PerformanceTest
5
+ # Refer to the documentation for all available options
6
+ # self.profile_options = { :runs => 5, :metrics => [:wall_time, :memory]
7
+ # :output => 'tmp/performance', :formats => [:flat] }
8
+
9
+ def test_homepage
10
+ get '/'
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ ENV["RAILS_ENV"] = "test"
2
+ require File.expand_path('../../config/environment', __FILE__)
3
+ require 'rails/test_help'
4
+
5
+ class ActiveSupport::TestCase
6
+ # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
7
+ #
8
+ # Note: You'll currently still have to declare fixtures explicitly in integration tests
9
+ # -- they do not yet inherit this setting
10
+ fixtures :all
11
+
12
+ # Add more helper methods to be used by all tests here...
13
+ end
File without changes
@@ -0,0 +1,4 @@
1
+ require 'test_helper'
2
+
3
+ class MerchantsHelperTest < ActionView::TestCase
4
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class MerchantTest < ActiveSupport::TestCase
4
+ # test "the truth" do
5
+ # assert true
6
+ # end
7
+ end
File without changes
File without changes
File without changes
@@ -3,11 +3,14 @@ require 'uri'
3
3
  require 'cgi'
4
4
  require 'openssl'
5
5
  require 'base64'
6
+ require 'active_merchant/billing/gateways/paypal_permissions/x_pp_authorization'
6
7
 
7
8
 
8
9
  module ActiveMerchant #:nodoc:
9
10
  module Billing #:nodoc:
10
11
  class PaypalPermissionsGateway < Gateway # :nodoc
12
+ include XPPAuthorization
13
+
11
14
  public
12
15
  def self.setup
13
16
  yield self
@@ -16,18 +19,44 @@ module ActiveMerchant #:nodoc:
16
19
  public
17
20
  def initialize(options = {})
18
21
  requires!(options, :login, :password, :signature, :app_id)
22
+ @login = options.delete(:login)
23
+ @password = options.delete(:password)
24
+ @app_id = options.delete(:app_id)
25
+ @api_signature = options.delete(:signature)
19
26
  request_permissions_headers = {
20
- 'X-PAYPAL-SECURITY-USERID' => options.delete(:login),
21
- 'X-PAYPAL-SECURITY-PASSWORD' => options.delete(:password),
22
- 'X-PAYPAL-SECURITY-SIGNATURE' => options.delete(:signature),
23
- 'X-PAYPAL-APPLICATION-ID' => options.delete(:app_id),
27
+ 'X-PAYPAL-SECURITY-USERID' => @login,
28
+ 'X-PAYPAL-SECURITY-PASSWORD' => @password,
29
+ 'X-PAYPAL-SECURITY-SIGNATURE' => @api_signature,
30
+ 'X-PAYPAL-APPLICATION-ID' => @app_id,
24
31
  'X-PAYPAL-REQUEST-DATA-FORMAT' => 'NV',
25
32
  'X-PAYPAL-RESPONSE-DATA-FORMAT' => 'NV',
26
33
  }
27
34
  get_access_token_headers = request_permissions_headers.dup
35
+ get_basic_personal_data_headers = lambda { |access_token, access_token_verifier|
36
+ {
37
+ 'X-PAYPAL-SECURITY-USERID' => @login,
38
+ 'X-PAYPAL-SECURITY-PASSWORD' => @password,
39
+ 'X-PAYPAL-SECURITY-SIGNATURE' => @api_signature,
40
+ 'X-PAYPAL-APPLICATION-ID' => @app_id,
41
+ 'X-PAYPAL-REQUEST-DATA-FORMAT' => 'NV',
42
+ 'X-PAYPAL-RESPONSE-DATA-FORMAT' => 'NV',
43
+ }.update(x_pp_authorization_header(get_basic_personal_data_url, access_token, access_token_verifier))
44
+ }
45
+ get_advanced_personal_data_headers = lambda { |access_token, access_token_verifier|
46
+ {
47
+ 'X-PAYPAL-SECURITY-USERID' => @login,
48
+ 'X-PAYPAL-SECURITY-PASSWORD' => @password,
49
+ 'X-PAYPAL-SECURITY-SIGNATURE' => @api_signature,
50
+ 'X-PAYPAL-APPLICATION-ID' => @app_id,
51
+ 'X-PAYPAL-REQUEST-DATA-FORMAT' => 'NV',
52
+ 'X-PAYPAL-RESPONSE-DATA-FORMAT' => 'NV',
53
+ }.update(x_pp_authorization_header(get_advanced_personal_data_url, access_token, access_token_verifier))
54
+ }
28
55
  @options = {
29
56
  :request_permissions_headers => request_permissions_headers,
30
57
  :get_access_token_headers => get_access_token_headers,
58
+ :get_basic_personal_data_headers => get_basic_personal_data_headers,
59
+ :get_advanced_personal_data_headers => get_advanced_personal_data_headers,
31
60
  }.update(options)
32
61
  super
33
62
  end
@@ -37,8 +66,8 @@ module ActiveMerchant #:nodoc:
37
66
  query_string = build_request_permissions_query_string callback_url, scope
38
67
  nvp_response = ssl_get "#{request_permissions_url}?#{query_string}", @options[:request_permissions_headers]
39
68
  if nvp_response =~ /error\(\d+\)/
40
- puts "request: #{request_permissions_url}?#{query_string}\n"
41
- puts "nvp_response: #{nvp_response}\n"
69
+ # puts "request: #{request_permissions_url}?#{query_string}\n"
70
+ # puts "nvp_response: #{nvp_response}\n"
42
71
  end
43
72
  response = parse_request_permissions_nvp(nvp_response)
44
73
  end
@@ -53,8 +82,8 @@ module ActiveMerchant #:nodoc:
53
82
  query_string = build_get_access_token_query_string request_token, request_token_verifier
54
83
  nvp_response = ssl_get "#{get_access_token_url}?#{query_string}", @options[:get_access_token_headers]
55
84
  if nvp_response =~ /error\(\d+\)/
56
- puts "request: #{get_access_token_url}?#{query_string}\n"
57
- puts "nvp_response: #{nvp_response}\n"
85
+ # puts "request: #{get_access_token_url}?#{query_string}\n"
86
+ # puts "nvp_response: #{nvp_response}\n"
58
87
  end
59
88
  response = parse_get_access_token_nvp(nvp_response)
60
89
  end
@@ -65,6 +94,53 @@ module ActiveMerchant #:nodoc:
65
94
  template % token
66
95
  end
67
96
 
97
+ def basic_personal_data_mappings
98
+ {
99
+ "http://axschema.org/contact/country/home" => :country,
100
+ "http://axschema.org/contact/email" => :email,
101
+ "http://axschema.org/namePerson/first" => :first_name,
102
+ "http://axschema.org/namePerson/last" => :last_name,
103
+ "http://schema.openid.net/contact/fullname" => :full_name,
104
+ "https://www.paypal.com/webapps/auth/schema/payerID" => :payer_id,
105
+ }
106
+ end
107
+
108
+ def advanced_personal_data_mappings
109
+ {
110
+ "http://axschema.org/birthDate" => :birthdate,
111
+ "http://schema.openid.net/contact/street1" => :street1,
112
+ "http://schema.openid.net/contact/street2" => :street2,
113
+ "http://axschema.org/contact/city/home" => :city,
114
+ "http://axschema.org/contact/state/home" => :state,
115
+ "http://axschema.org/contact/postalCode/home" => :postal_code,
116
+ "http://axschema.org/contact/phone/default" => :phone,
117
+ }
118
+ end
119
+
120
+ public
121
+ def get_basic_personal_data(access_token, access_token_verifier)
122
+ body = personal_data_post_body(basic_personal_data_mappings)
123
+ opts = @options[:get_basic_personal_data_headers].call(access_token, access_token_verifier)
124
+ nvp_response = ssl_post(get_basic_personal_data_url, body, opts)
125
+ if nvp_response =~ /error\(\d+\)/
126
+ # puts "request: #{get_basic_personal_data_url} post_body:#{body}\n"
127
+ # puts "nvp_response: #{nvp_response}\n"
128
+ end
129
+ response = parse_personal_data_nvp(nvp_response, basic_personal_data_mappings)
130
+ end
131
+
132
+ public
133
+ def get_advanced_personal_data(access_token, access_token_verifier)
134
+ body = personal_data_post_body(advanced_personal_data_mappings)
135
+ opts = @options[:get_advanced_personal_data_headers].call(access_token, access_token_verifier)
136
+ nvp_response = ssl_post(get_advanced_personal_data_url, body, opts)
137
+ if nvp_response =~ /error\(\d+\)/
138
+ # puts "request: #{get_advanced_personal_data_url} post_body:#{body}\n"
139
+ # puts "nvp_response: #{nvp_response}\n"
140
+ end
141
+ response = parse_personal_data_nvp(nvp_response, advanced_personal_data_mappings)
142
+ end
143
+
68
144
  public
69
145
  def get_access_token_url
70
146
  test? ? URLS[:test][:get_access_token] : URLS[:live][:get_access_token]
@@ -75,6 +151,16 @@ module ActiveMerchant #:nodoc:
75
151
  test? ? URLS[:test][:get_permissions] : URLS[:live][:get_permissions]
76
152
  end
77
153
 
154
+ public
155
+ def get_basic_personal_data_url
156
+ test? ? URLS[:test][:get_basic_personal_data] : URLS[:live][:get_basic_personal_data]
157
+ end
158
+
159
+ public
160
+ def get_advanced_personal_data_url
161
+ test? ? URLS[:test][:get_advanced_personal_data] : URLS[:live][:get_advanced_personal_data]
162
+ end
163
+
78
164
  private
79
165
  URLS = {
80
166
  :test => {
@@ -82,12 +168,16 @@ module ActiveMerchant #:nodoc:
82
168
  :redirect_user_to_paypal => 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_grant-permission&request_token=%s',
83
169
  :get_access_token => 'https://svcs.sandbox.paypal.com/Permissions/GetAccessToken',
84
170
  :get_permissions => 'https://svcs.sandbox.paypal.com/Permissions/GetPermissions',
171
+ :get_basic_personal_data => 'https://svcs.sandbox.paypal.com/Permissions/GetBasicPersonalData',
172
+ :get_advanced_personal_data => 'https://svcs.sandbox.paypal.com/Permissions/GetAdvancedPersonalData',
85
173
  },
86
174
  :live => {
87
175
  :request_permissions => 'https://svcs.paypal.com/Permissions/RequestPermissions',
88
176
  :redirect_user_to_paypal => 'https://www.paypal.com/cgi-bin/webscr?cmd=_grant-permission&request_token=%s',
89
177
  :get_access_token => 'https://svcs.paypal.com/Permissions/GetAccessToken',
90
- :get_permissions => 'https://svcs.sandbox.paypal.com/Permissions/GetPermissions',
178
+ :get_permissions => 'https://www.paypal.com/Permissions/GetPermissions',
179
+ :get_basic_personal_data => 'https://www.paypal.com/Permissions/GetBasicPersonalData',
180
+ :get_advanced_personal_data => 'https://www.paypal.com/Permissions/GetAdvancedPersonalData',
91
181
  }
92
182
  }
93
183
 
@@ -114,13 +204,14 @@ module ActiveMerchant #:nodoc:
114
204
  "requestEnvelope.errorLanguage=en_US&token=#{request_token}&verifier=#{verifier}"
115
205
  end
116
206
 
117
- =begin
118
207
  private
119
- def setup_request_permission
120
- callback
121
- scope
208
+ def personal_data_post_body(personal_data_mappings)
209
+ body = ""
210
+ personal_data_mappings.keys.each_with_index do |v, idx|
211
+ body += "attributeList.attribute(#{idx})=#{v}&"
212
+ end
213
+ body += "requestEnvelope.errorLanguage=en_US"
122
214
  end
123
- =end
124
215
 
125
216
  private
126
217
  def parse_request_permissions_nvp(nvp)
@@ -154,8 +245,8 @@ module ActiveMerchant #:nodoc:
154
245
  # do nothing
155
246
  when "token"
156
247
  response[:token] = v
157
- when /^error\((?<error_idx>\d+)\)/
158
- error_idx = error_idx.to_i
248
+ when /^error\((\d+)\)/
249
+ error_idx = $1.to_i
159
250
  if response[:errors].length <= error_idx
160
251
  response[:errors] << { :parameters => [] }
161
252
  raise if response[:errors].length <= error_idx
@@ -181,8 +272,8 @@ module ActiveMerchant #:nodoc:
181
272
  response[:errors][error_idx][:category] = v
182
273
  when /^error\(\d+\)\.message$/
183
274
  response[:errors][error_idx][:message] = v
184
- when /^error\(\d+\)\.parameter\((?<parameter_idx>\d+)\)$/
185
- parameter_idx = parameter_idx.to_i
275
+ when /^error\(\d+\)\.parameter\((\d+)\)$/
276
+ parameter_idx = $1.to_i
186
277
  if response[:errors][error_idx][:parameters].length <= parameter_idx
187
278
  response[:errors][error_idx][:parameters] << {}
188
279
  raise if response[:errors][error_idx][:parameters].length <= parameter_idx
@@ -228,8 +319,8 @@ module ActiveMerchant #:nodoc:
228
319
  response[:token] = v
229
320
  when "tokenSecret"
230
321
  response[:tokenSecret] = v
231
- when /^error\((?<error_idx>\d+)\)/
232
- error_idx = error_idx.to_i
322
+ when /^error\((\d+)\)/
323
+ error_idx = $1.to_i
233
324
  if response[:errors].length <= error_idx
234
325
  response[:errors] << { :parameters => [] }
235
326
  raise if response[:errors].length <= error_idx
@@ -255,8 +346,8 @@ module ActiveMerchant #:nodoc:
255
346
  response[:errors][error_idx][:category] = v
256
347
  when /^error\(\d+\)\.message$/
257
348
  response[:errors][error_idx][:message] = v
258
- when /^error\(\d+\)\.parameter\((?<parameter_idx>\d+)\)$/
259
- parameter_idx = parameter_idx.to_i
349
+ when /^error\(\d+\)\.parameter\((\d+)\)$/
350
+ parameter_idx = $1.to_i
260
351
  if response[:errors][error_idx][:parameters].length <= parameter_idx
261
352
  response[:errors][error_idx][:parameters] << {}
262
353
  raise if response[:errors][error_idx][:parameters].length <= parameter_idx
@@ -269,72 +360,112 @@ module ActiveMerchant #:nodoc:
269
360
  end
270
361
 
271
362
  private
272
- def authentication_header url
273
- timestamp = Time.now.to_i
274
- signature = authentication_signature url, timestamp
275
- { 'X-PAYPAL-AUTHORIZATION' => "token=#{access_token}, signature=#{signature}, timeStamp=#{timestamp}" }
276
- end
277
-
278
- private
279
- def authentication_signature url, timestamp
280
- # no query params, but if there were, this is where they'd go
281
- query_params = {}
282
- key = [ password, verifier ].join("&")
283
- params = query_params.dup.merge({
284
- "oauth_consumer_key" => @options[:request_permissions_headers]['X-PAYPAL-SECURITY-USERID'],
285
- "oauth_version" => "1.0",
286
- "oauth_signature_method" => "HMAC-SHA1",
287
- "oauth_token" => access_token,
288
- "oauth_timestamp" => timestamp,
289
- })
290
- sorted_params = Hash[params.sort]
291
- sorted_query_string = sorted_params.to_query
292
- data = [ "POST", url, sorted_query_string ].join("&") # ? "https://api-3t.sandbox.paypal.com/nvp"
293
- digest = OpenSSL::Digest::Digest.new('sha1')
294
- OpenSSL::HMAC.digest(digest, key, data)
295
- enc = Base64.encode64('Send reinforcements') # encode per RFC 2045 (not 4648
296
- end
297
-
363
+ def parse_personal_data_nvp(nvp, personal_data_mappings)
364
+ response = {
365
+ :raw_response => nvp,
366
+ :errors => [
367
+ ],
368
+ :personal_data => {
369
+ }
370
+ }
371
+ begin
372
+ key = nil
373
+ key_idx = nil
374
+ pairs = nvp.split "&"
375
+ pairs.each do |pair|
376
+ n,v = pair.split "="
377
+ v = "" if v.nil?
378
+ n = CGI.unescape n
379
+ v = CGI.unescape v
380
+ case n
381
+ when "responseEnvelope.timestamp"
382
+ response[:timestamp] = v
383
+ when "responseEnvelope.ack"
384
+ response[:ack] = v
385
+ when "responseEnvelope.correlationId"
386
+ response[:correlation_id] = v
387
+ when "responseEnvelope.build"
388
+ # do nothing
298
389
 
390
+ when /response\.personalData\((\d+)\)\.personalDataKey/
391
+ key_idx = $1.to_i
392
+ key = personal_data_mappings[v]
299
393
  =begin
300
- public static Map getAuthHeader(String apiUserName, String apiPassword,
301
- String accessToken, String tokenSecret, HTTPMethod httpMethod,
302
- String scriptURI,Map queryParams) throws OAuthException {
303
-
304
- Map headers=new HashMap();
305
- String consumerKey = apiUserName;
306
- String consumerSecretStr = apiPassword;
307
- String time = String.valueOf(System.currentTimeMillis()/1000);
308
-
309
- OAuthSignature oauth = new OAuthSignature(consumerKey,consumerSecretStr);
310
- if(HTTPMethod.GET.equals(httpMethod) && queryParams != null){
311
- Iterator itr = queryParams.entrySet().iterator();
312
- while (itr.hasNext()) {
313
- Map.Entry param = (Map.Entry)itr.next();
314
- String key=(String)param.getKey();
315
- String value=(String)param.getValue();
316
- oauth.addParameter(key,value);
317
- }
318
- }
319
- oauth.setToken(accessToken);
320
- oauth.setTokenSecret(tokenSecret);
321
- oauth.setHTTPMethod(httpMethod);
322
- oauth.setTokenTimestamp(time);
323
- oauth.setRequestURI(scriptURI);
324
- //Compute Signature
325
- String sig = oauth.computeV1Signature();
326
-
327
- headers.put("Signature", sig);
328
- headers.put("TimeStamp", time);
329
- return headers;
330
-
331
- }
394
+ case v
395
+ when "http://axschema.org/contact/country/home"
396
+ key = :country
397
+ when "http://axschema.org/contact/email"
398
+ key = :email
399
+ when "http://axschema.org/namePerson/first"
400
+ key = :first_name
401
+ when "http://axschema.org/namePerson/last"
402
+ key = :last_name
403
+ when "http://schema.openid.net/contact/fullname"
404
+ key = :full_name
405
+ when "https://www.paypal.com/webapps/auth/schema/payerID"
406
+ key = :payer_id
407
+ end
332
408
  =end
333
409
 
410
+ when /response\.personalData\((\d+)\)\.personalDataValue/
411
+ val_idx = $1.to_i
412
+ if !key
413
+ # puts "key:#{key} is nil for v:#{v}"
414
+ elsif val_idx != key_idx
415
+ # puts "key_idx:#{key_idx} is out of sync with val_idx:#{val_idx} for key:#{key}"
416
+ else
417
+ response[:personal_data][key] = v
418
+ end
419
+
420
+ when /^error\((\d+)\)/
421
+ error_idx = $1.to_i
422
+ if response[:errors].length <= error_idx
423
+ response[:errors] << { :parameters => [] }
424
+ raise if response[:errors].length <= error_idx
425
+ end
426
+ case n
427
+ when /^error\(\d+\)\.errorId$/
428
+ response[:errors][error_idx][:error_id] = v
429
+ =begin
430
+ # Client should implement these with logging. PayPal doesn't distinguish
431
+ # between errors which can be corrected by the user and errors which need
432
+ # to be corrected by a developer or merchant, say, in configuration.
433
+ # case v
434
+ # when "520002"
435
+ # when
436
+ =end
437
+ when /^error\(\d+\)\.domain$/
438
+ response[:errors][error_idx][:domain] = v
439
+ when /^error\(\d+\)\.subdomain$/
440
+ response[:errors][error_idx][:subdomain] = v
441
+ when /^error\(\d+\)\.severity$/
442
+ response[:errors][error_idx][:severity] = v
443
+ when /^error\(\d+\)\.category$/
444
+ response[:errors][error_idx][:category] = v
445
+ when /^error\(\d+\)\.message$/
446
+ response[:errors][error_idx][:message] = v
447
+ when /^error\(\d+\)\.parameter\((\d+)\)$/
448
+ parameter_idx = $1.to_i
449
+ if response[:errors][error_idx][:parameters].length <= parameter_idx
450
+ response[:errors][error_idx][:parameters] << {}
451
+ raise if response[:errors][error_idx][:parameters].length <= parameter_idx
452
+ end
453
+ response[:errors][error_idx][:parameters][parameter_idx] = v
454
+ end
455
+ end
456
+ end
457
+ rescue
458
+ response[:errors][:unknown_error] << nvp.inspect
459
+ end
460
+ response
461
+ end
462
+
463
+ =begin
334
464
  private
335
465
  def setup_purchase(options)
336
466
  commit('Pay', build_adaptive_payment_pay_request(options))
337
467
  end
468
+ =end
338
469
  end
339
470
  end
340
471
  end