paypal_permissions 0.0.3.3 → 0.0.3.4

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.
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