pippin 0.1.1 → 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/.travis.yml +6 -0
- data/Gemfile +1 -1
- data/HISTORY +5 -0
- data/README.textile +19 -7
- data/config/routes.rb +1 -3
- data/lib/pippin.rb +6 -10
- data/lib/pippin/app.rb +17 -0
- data/lib/pippin/engine.rb +0 -1
- data/lib/pippin/ipn.rb +4 -1
- data/pippin.gemspec +2 -3
- data/spec/pippin/ipn_spec.rb +12 -0
- data/spec/requests/ipn_submission_spec.rb +11 -3
- data/spec/spec_helper.rb +1 -0
- metadata +104 -65
- data/app/controllers/pippin/ipns_controller.rb +0 -16
- data/lib/pippin/version.rb +0 -3
- data/spec/controllers/pippin/ipns_controller_spec.rb +0 -49
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/HISTORY
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
1.0.0 - September 25th 2012
|
2
|
+
* Rails/ActiveSupport 3.1 or better.
|
3
|
+
* No listener - use ActiveSupport::Notifications instead.
|
4
|
+
* No controller - just as easy running things as a simple Rack app.
|
5
|
+
|
1
6
|
0.1.1 - January 4th 2012
|
2
7
|
* Don't require a specific version of Rails, just 3.0 or better.
|
3
8
|
|
data/README.textile
CHANGED
@@ -2,25 +2,37 @@ h1. Pippin
|
|
2
2
|
|
3
3
|
Pippin is a Rails Engine for processing PayPal IPN requests. It automatically adds a route to your Rails application that validates and processes IPNs.
|
4
4
|
|
5
|
-
If you want to do something with those IPN objects (and I recommend you do), then all you need to do is attach a
|
5
|
+
If you want to do something with those IPN objects (and I recommend you do), then all you need to do is attach a subscriber to the notification, and that'll fire as each valid IPN is received.
|
6
|
+
|
7
|
+
*Using Rails 3.0?* Then you better jump back to the "0.1.1 release":https://github.com/pat/pippin/tree/v0.1.1 of this library, which does not use ActiveSupport::Notifications.
|
6
8
|
|
7
9
|
h2. Installation and Usage
|
8
10
|
|
9
11
|
Just add it to your Gemfile:
|
10
12
|
|
11
|
-
<pre><code>gem 'pippin', '~> 0.
|
13
|
+
<pre><code>gem 'pippin', '~> 1.0.0'</code></pre>
|
12
14
|
|
13
|
-
Then
|
15
|
+
Then somewhere (perhaps in an initializer), subscribe to the notifications:
|
14
16
|
|
15
|
-
<pre><code
|
16
|
-
|
17
|
+
<pre><code>ActiveSupport::Notifications.subscribe('received.ipn') do |*args|
|
18
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
19
|
+
ipn = event.payload[:ipn]
|
17
20
|
# use IPN data
|
18
21
|
ipn.params # => {'business' => 'email@domain.com', 'txn_type' => ...}
|
19
|
-
|
22
|
+
end</code></pre>
|
23
|
+
|
24
|
+
There are also notifications fired using the txn_type parameter as the prefix, if you wish to subscribe to certain types:
|
25
|
+
|
26
|
+
<pre><code>ActiveSupport::Notifications.subscribe('subscr_signup.ipn') do |*args|
|
27
|
+
event = ActiveSupport::Notifications::Event.new(*args)
|
28
|
+
ipn = event.payload[:ipn]
|
29
|
+
|
30
|
+
# A subscription sign up has happened. Do something!
|
31
|
+
end</code></pre>
|
20
32
|
|
21
33
|
Any parameters with the suffix '_date' in their name will automatically be translated from PayPal's ugly date string to an appropriate Time object.
|
22
34
|
|
23
|
-
When constructing your form that redirects people to PayPal, you'll want to set the @notify_url@ parameter to use Pippin's URL that has automatically been added to your routes: @
|
35
|
+
When constructing your form that redirects people to PayPal, you'll want to set the @notify_url@ parameter to use Pippin's URL that has automatically been added to your routes: @'pippin/ipns'@.
|
24
36
|
|
25
37
|
h2. Contributing
|
26
38
|
|
data/config/routes.rb
CHANGED
data/lib/pippin.rb
CHANGED
@@ -1,15 +1,11 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_support/notifications'
|
2
|
+
require 'active_support/core_ext/module/delegation'
|
2
3
|
|
3
4
|
module Pippin
|
4
|
-
|
5
|
-
@listener
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.listener=(listener)
|
9
|
-
@listener = listener
|
10
|
-
end
|
5
|
+
#
|
11
6
|
end
|
12
7
|
|
13
|
-
require 'pippin/
|
8
|
+
require 'pippin/app'
|
14
9
|
require 'pippin/ipn'
|
15
|
-
|
10
|
+
|
11
|
+
require 'pippin/engine' if defined?(Rails)
|
data/lib/pippin/app.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class Pippin::App
|
2
|
+
delegate :instrument, :to => ActiveSupport::Notifications
|
3
|
+
|
4
|
+
def call(env)
|
5
|
+
request = Rack::Request.new(env)
|
6
|
+
ipn = Pippin::IPN.new request.params, request.body.read
|
7
|
+
|
8
|
+
if ipn.valid?
|
9
|
+
instrument 'received.ipn', :ipn => ipn
|
10
|
+
instrument "#{ipn.params['txn_type']}.ipn", :ipn => ipn
|
11
|
+
|
12
|
+
[200, {}, [' ']]
|
13
|
+
else
|
14
|
+
[400, {}, [' ']]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/pippin/engine.rb
CHANGED
data/lib/pippin/ipn.rb
CHANGED
@@ -38,6 +38,9 @@ class Pippin::IPN
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def paypal_uri
|
41
|
-
|
41
|
+
domain = 'www.paypal.com'
|
42
|
+
domain = 'www.sandbox.paypal.com' if params['test_ipn'] == '1'
|
43
|
+
|
44
|
+
"https://#{domain}/cgi-bin/webscr?cmd=_notify-validate&#{body}"
|
42
45
|
end
|
43
46
|
end
|
data/pippin.gemspec
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
$:.push File.expand_path('../lib', __FILE__)
|
3
|
-
require 'pippin/version'
|
4
3
|
|
5
4
|
Gem::Specification.new do |s|
|
6
5
|
s.name = 'pippin'
|
7
|
-
s.version =
|
6
|
+
s.version = '1.0.0'
|
8
7
|
s.authors = ['Pat Allan']
|
9
8
|
s.email = ['pat@freelancing-gods.com']
|
10
9
|
s.homepage = ''
|
@@ -18,7 +17,7 @@ Gem::Specification.new do |s|
|
|
18
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
18
|
s.require_paths = ['lib']
|
20
19
|
|
21
|
-
s.add_runtime_dependency '
|
20
|
+
s.add_runtime_dependency 'activesupport', '>= 3.1'
|
22
21
|
|
23
22
|
s.add_development_dependency 'fakeweb', '1.3.0'
|
24
23
|
s.add_development_dependency 'fakeweb-matcher', '1.2.2'
|
data/spec/pippin/ipn_spec.rb
CHANGED
@@ -22,6 +22,18 @@ describe Pippin::IPN do
|
|
22
22
|
'https://www.paypal.com/cgi-bin/webscr?cmd=_notify-validate&foo=bar')
|
23
23
|
end
|
24
24
|
|
25
|
+
it "checks the validity in the sandbox if it is a test IPN" do
|
26
|
+
FakeWeb.register_uri :get,
|
27
|
+
/^https:\/\/www\.sandbox\.paypal\.com\/cgi-bin\/webscr/,
|
28
|
+
:body => 'VERIFIED'
|
29
|
+
|
30
|
+
ipn = Pippin::IPN.new({'test_ipn' => '1'}, 'foo=bar')
|
31
|
+
ipn.valid?
|
32
|
+
|
33
|
+
FakeWeb.should have_requested(:get,
|
34
|
+
'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_notify-validate&foo=bar')
|
35
|
+
end
|
36
|
+
|
25
37
|
it "returns true if PayPal confirms the validity of the data" do
|
26
38
|
FakeWeb.register_uri :get, /^https:\/\/www\.paypal\.com\/cgi-bin\/webscr/,
|
27
39
|
:body => 'VERIFIED'
|
@@ -13,12 +13,16 @@ describe 'IPN Submission' do
|
|
13
13
|
response.status.should == 200
|
14
14
|
end
|
15
15
|
|
16
|
-
it "calls the provided
|
16
|
+
it "calls the provided subscriber" do
|
17
17
|
ipn_lodged = false
|
18
|
-
|
18
|
+
sub = ActiveSupport::Notifications.subscribe('received.ipn') { |payload|
|
19
|
+
ipn_lodged = true
|
20
|
+
}
|
19
21
|
|
20
22
|
post '/pippin/ipns'
|
21
23
|
|
24
|
+
ActiveSupport::Notifications.unsubscribe sub
|
25
|
+
|
22
26
|
ipn_lodged.should be_true
|
23
27
|
end
|
24
28
|
end
|
@@ -37,10 +41,14 @@ describe 'IPN Submission' do
|
|
37
41
|
|
38
42
|
it "does not call the provided listener" do
|
39
43
|
ipn_lodged = false
|
40
|
-
|
44
|
+
sub = ActiveSupport::Notifications.subscribe('received.ipn') { |payload|
|
45
|
+
ipn_lodged = true
|
46
|
+
}
|
41
47
|
|
42
48
|
post '/pippin/ipns'
|
43
49
|
|
50
|
+
ActiveSupport::Notifications.unsubscribe sub
|
51
|
+
|
44
52
|
ipn_lodged.should be_false
|
45
53
|
end
|
46
54
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,125 +1,164 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: pippin
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Pat Allan
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
|
18
|
+
date: 2012-09-25 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: activesupport
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
17
24
|
none: false
|
18
|
-
requirements:
|
19
|
-
- -
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 5
|
29
|
+
segments:
|
30
|
+
- 3
|
31
|
+
- 1
|
32
|
+
version: "3.1"
|
22
33
|
type: :runtime
|
23
|
-
|
24
|
-
|
25
|
-
- !ruby/object:Gem::Dependency
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
26
36
|
name: fakeweb
|
27
|
-
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
28
39
|
none: false
|
29
|
-
requirements:
|
30
|
-
- - =
|
31
|
-
- !ruby/object:Gem::Version
|
40
|
+
requirements:
|
41
|
+
- - "="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 27
|
44
|
+
segments:
|
45
|
+
- 1
|
46
|
+
- 3
|
47
|
+
- 0
|
32
48
|
version: 1.3.0
|
33
49
|
type: :development
|
34
|
-
|
35
|
-
|
36
|
-
- !ruby/object:Gem::Dependency
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
37
52
|
name: fakeweb-matcher
|
38
|
-
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
39
55
|
none: false
|
40
|
-
requirements:
|
41
|
-
- - =
|
42
|
-
- !ruby/object:Gem::Version
|
56
|
+
requirements:
|
57
|
+
- - "="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 27
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 2
|
63
|
+
- 2
|
43
64
|
version: 1.2.2
|
44
65
|
type: :development
|
45
|
-
|
46
|
-
|
47
|
-
- !ruby/object:Gem::Dependency
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
48
68
|
name: rspec-rails
|
49
|
-
|
69
|
+
prerelease: false
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
50
71
|
none: false
|
51
|
-
requirements:
|
52
|
-
- - =
|
53
|
-
- !ruby/object:Gem::Version
|
72
|
+
requirements:
|
73
|
+
- - "="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 19
|
76
|
+
segments:
|
77
|
+
- 2
|
78
|
+
- 7
|
79
|
+
- 0
|
54
80
|
version: 2.7.0
|
55
81
|
type: :development
|
56
|
-
|
57
|
-
|
58
|
-
- !ruby/object:Gem::Dependency
|
82
|
+
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
59
84
|
name: sqlite3
|
60
|
-
|
85
|
+
prerelease: false
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
61
87
|
none: false
|
62
|
-
requirements:
|
63
|
-
- - =
|
64
|
-
- !ruby/object:Gem::Version
|
88
|
+
requirements:
|
89
|
+
- - "="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 17
|
92
|
+
segments:
|
93
|
+
- 1
|
94
|
+
- 3
|
95
|
+
- 5
|
65
96
|
version: 1.3.5
|
66
97
|
type: :development
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
listener.
|
71
|
-
email:
|
98
|
+
version_requirements: *id005
|
99
|
+
description: Accepts IPN requests, validates them and passes them on to a defined listener.
|
100
|
+
email:
|
72
101
|
- pat@freelancing-gods.com
|
73
102
|
executables: []
|
103
|
+
|
74
104
|
extensions: []
|
105
|
+
|
75
106
|
extra_rdoc_files: []
|
76
|
-
|
107
|
+
|
108
|
+
files:
|
77
109
|
- .gitignore
|
110
|
+
- .travis.yml
|
78
111
|
- Gemfile
|
79
112
|
- HISTORY
|
80
113
|
- LICENCE
|
81
114
|
- README.textile
|
82
115
|
- Rakefile
|
83
|
-
- app/controllers/pippin/ipns_controller.rb
|
84
116
|
- config.ru
|
85
117
|
- config/routes.rb
|
86
118
|
- lib/pippin.rb
|
119
|
+
- lib/pippin/app.rb
|
87
120
|
- lib/pippin/engine.rb
|
88
121
|
- lib/pippin/ipn.rb
|
89
|
-
- lib/pippin/version.rb
|
90
122
|
- pippin.gemspec
|
91
|
-
- spec/controllers/pippin/ipns_controller_spec.rb
|
92
123
|
- spec/internal/log/.gitignore
|
93
124
|
- spec/internal/public/favicon.ico
|
94
125
|
- spec/pippin/ipn_spec.rb
|
95
126
|
- spec/requests/ipn_submission_spec.rb
|
96
127
|
- spec/spec_helper.rb
|
97
|
-
homepage:
|
128
|
+
homepage: ""
|
98
129
|
licenses: []
|
130
|
+
|
99
131
|
post_install_message:
|
100
132
|
rdoc_options: []
|
101
|
-
|
133
|
+
|
134
|
+
require_paths:
|
102
135
|
- lib
|
103
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
137
|
none: false
|
105
|
-
requirements:
|
106
|
-
- -
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
|
109
|
-
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
hash: 3
|
142
|
+
segments:
|
143
|
+
- 0
|
144
|
+
version: "0"
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
146
|
none: false
|
111
|
-
requirements:
|
112
|
-
- -
|
113
|
-
- !ruby/object:Gem::Version
|
114
|
-
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
hash: 3
|
151
|
+
segments:
|
152
|
+
- 0
|
153
|
+
version: "0"
|
115
154
|
requirements: []
|
155
|
+
|
116
156
|
rubyforge_project: pippin
|
117
|
-
rubygems_version: 1.8.
|
157
|
+
rubygems_version: 1.8.16
|
118
158
|
signing_key:
|
119
159
|
specification_version: 3
|
120
160
|
summary: A PayPal Rails Engine that handles IPNs
|
121
|
-
test_files:
|
122
|
-
- spec/controllers/pippin/ipns_controller_spec.rb
|
161
|
+
test_files:
|
123
162
|
- spec/internal/log/.gitignore
|
124
163
|
- spec/internal/public/favicon.ico
|
125
164
|
- spec/pippin/ipn_spec.rb
|
@@ -1,16 +0,0 @@
|
|
1
|
-
class Pippin::IpnsController < ActionController::Base
|
2
|
-
def create
|
3
|
-
if ipn.valid?
|
4
|
-
Pippin.listener.call ipn if Pippin.listener
|
5
|
-
head :ok
|
6
|
-
else
|
7
|
-
head :bad_request
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def ipn
|
14
|
-
@ipn ||= Pippin::IPN.new params, request.body.read
|
15
|
-
end
|
16
|
-
end
|
data/lib/pippin/version.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Pippin::IpnsController do
|
4
|
-
describe '#create' do
|
5
|
-
let(:ipn) { double('IPN') }
|
6
|
-
let(:block) { double('block', :call => true) }
|
7
|
-
|
8
|
-
before :each do
|
9
|
-
Pippin::IPN.stub :new => ipn
|
10
|
-
Pippin.stub :listener => block
|
11
|
-
end
|
12
|
-
|
13
|
-
context 'valid IPN' do
|
14
|
-
before :each do
|
15
|
-
ipn.stub :valid? => true
|
16
|
-
end
|
17
|
-
|
18
|
-
it "responds with 200" do
|
19
|
-
post :create
|
20
|
-
|
21
|
-
response.status.should == 200
|
22
|
-
end
|
23
|
-
|
24
|
-
it "calls the listener with the IPN object" do
|
25
|
-
block.should_receive(:call).with(ipn)
|
26
|
-
|
27
|
-
post :create
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
context 'invalid IPN' do
|
32
|
-
before :each do
|
33
|
-
ipn.stub :valid? => false
|
34
|
-
end
|
35
|
-
|
36
|
-
it "responds with a 400" do
|
37
|
-
post :create
|
38
|
-
|
39
|
-
response.status.should == 400
|
40
|
-
end
|
41
|
-
|
42
|
-
it "does not call the listener" do
|
43
|
-
block.should_not_receive(:call)
|
44
|
-
|
45
|
-
post :create
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|