spree_coinbase 2.2.0.1
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.
- checksums.yaml +15 -0
- data/.gitignore +14 -0
- data/.rspec +1 -0
- data/Gemfile +6 -0
- data/LICENSE +26 -0
- data/README.md +42 -0
- data/Rakefile +15 -0
- data/app/assets/javascripts/spree/backend/spree_coinbase.js +2 -0
- data/app/assets/javascripts/spree/frontend/spree_coinbase.js +39 -0
- data/app/assets/stylesheets/spree/backend/spree_coinbase.css +4 -0
- data/app/assets/stylesheets/spree/frontend/spree_coinbase.css +4 -0
- data/app/controllers/spree/ca-coinbase.crt +44 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +15 -0
- data/app/controllers/spree/coinbase_controller.rb +181 -0
- data/app/models/spree/coinbase_transaction.rb +10 -0
- data/app/models/spree/payment_method/coinbase.rb +23 -0
- data/app/views/spree/admin/payments/source_views/_coinbase.html.erb +5 -0
- data/app/views/spree/checkout/payment/_coinbase.html.erb +8 -0
- data/app/views/spree/coinbase/success.html.erb +2 -0
- data/bin/rails +7 -0
- data/config/locales/en.yml +4 -0
- data/config/routes.rb +6 -0
- data/db/migrate/20140330235546_create_spree_coinbase_transactions.rb +9 -0
- data/lib/generators/spree_coinbase/install/install_generator.rb +31 -0
- data/lib/spree_coinbase.rb +2 -0
- data/lib/spree_coinbase/engine.rb +15 -0
- data/spree_coinbase.gemspec +31 -0
- metadata +223 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NmI2ZWJiNDU1MDhhZWVhOTFmY2E2NWUyNjhlYTk5NDY0ZTc3MjM3MQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YzgzOTEyNWE2MjNlOTdlOTExZTYyZmY0YTQyNmM0YzMzM2FhMzFhMg==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmNlZmQ2MDgxM2ZmZjg5ZThhMTExYmQ3Nzc5NjJmNWJiZmI2Nzc4YzAxZDJl
|
10
|
+
ZjY3ZDVjNTM3NWU5NjUxNWE1YmQ2ZjZmNDMyYTRiNjhmNjUxMDYyNzRkMDAw
|
11
|
+
N2M4NWI0ZmRiN2JkMzNlNmQwZDQxNjZjZmEyOTVkYmM1ZTM3ZDM=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MDJmZTYzZTYwODY4Mjg3YTJhNGMxMzI5YjQwNTg5MDJjMWIxNzhjMmUyNTM5
|
14
|
+
ZTVhMmYwMzA0ZTQ2OGNjOGEwMjA1Y2VlYTVlYzViYmQ2OTU2ZWY3ZjE5NDYz
|
15
|
+
NGJmMDk5MzhkMTk3ZTYwMDQzMDhmNmZlNTBkZDMyNTc2ZGM3NWY=
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
Copyright (c) 2014 [name of plugin creator]
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name Spree nor the names of its contributors may be used to
|
13
|
+
endorse or promote products derived from this software without specific
|
14
|
+
prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
17
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
18
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
19
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
20
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
21
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
22
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
23
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
24
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
25
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
Spree Coinbase Plugin
|
2
|
+
=============
|
3
|
+
|
4
|
+
Accept bitcoin payments on your Spree store with the official Coinbase Spree plugin. For more information on Coinbase for merchants, visit https://coinbase.com/merchants.
|
5
|
+
|
6
|
+
Installation
|
7
|
+
------------
|
8
|
+
|
9
|
+
If you don't have a Coinbase account, sign up at https://coinbase.com/merchants. Coinbase offers daily payouts for merchants in the United States. For more infomation on setting up payouts, see https://coinbase.com/docs/merchant_tools/payouts.
|
10
|
+
|
11
|
+
Add spree_coinbase to your Gemfile:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'spree_coinbase'
|
15
|
+
```
|
16
|
+
|
17
|
+
Bundle your dependencies and run the installation generator:
|
18
|
+
|
19
|
+
```shell
|
20
|
+
bundle
|
21
|
+
bundle exec rails g spree_coinbase:install
|
22
|
+
```
|
23
|
+
|
24
|
+
After installing the gem, go to your Spree admin console and navigate to Configuration > Payment Methods > New Payment Method.
|
25
|
+
|
26
|
+

|
27
|
+
|
28
|
+
Select "Spree::PaymentMethod::Coinbase" from the "Provider" dropdown, enter a name (like "Bitcoin") for the payment method, and click "Create."
|
29
|
+
|
30
|
+

|
31
|
+
|
32
|
+
Go to https://coinbase.com/settings/api and click '+ New API Key' to generate an API key and secret for this plugin. You should create a 'HMAC' key with the permission 'merchant' only.
|
33
|
+
|
34
|
+
After generating the API key, click on the shortened representation of it (looks like 'kcyPDdpjgYk...') to view the full API Key + Secret. Copy and paste the API key and API secret into the respective fields on the Edit Payment Method page, then click "Update".
|
35
|
+
|
36
|
+
Remember to enable the API key on the https://coinbase.com/settings/api page by clicking the "Enable" link. If the API key is not enabled, the plugin will not work.
|
37
|
+
|
38
|
+

|
39
|
+
|
40
|
+
The plugin should now be active!
|
41
|
+
|
42
|
+
Copyright (c) 2014 Coinbase, released under the New BSD License
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'spree/testing_support/extension_rake'
|
6
|
+
|
7
|
+
RSpec::Core::RakeTask.new
|
8
|
+
|
9
|
+
task :default => [:spec]
|
10
|
+
|
11
|
+
desc 'Generates a dummy app for testing'
|
12
|
+
task :test_app do
|
13
|
+
ENV['LIB_NAME'] = 'spree_coinbase'
|
14
|
+
Rake::Task['extension:test_app'].invoke
|
15
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
SpreeCoinbase = {
|
2
|
+
doOnSiteCheckout: function() {
|
3
|
+
|
4
|
+
$('#checkout_form_payment input.continue').hide();
|
5
|
+
$('div[data-hook="checkout_payment_step"]').html("<iframe src=\"" + SpreeCoinbase.checkoutUrl + "\" style=\"width: 500px; height: 160px; border: none; overflow: hidden;\" scrolling=\"no\" allowtransparency=\"true\" frameborder=\"0\"></iframe>" +
|
6
|
+
"<p><a href=\"" + SpreeCoinbase.cancelUrl + "\">Cancel and choose another payment method</a></p>");
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
$(document).ready(function() {
|
11
|
+
$('#checkout_form_payment input.continue').click(function (e) {
|
12
|
+
checkedPaymentMethod = $('div[data-hook="checkout_payment_step"] input[type="radio"]:checked');
|
13
|
+
|
14
|
+
if (checkedPaymentMethod.val() == SpreeCoinbase.paymentMethodId && !SpreeCoinbase.useOffSite) {
|
15
|
+
// On-site checkout!
|
16
|
+
SpreeCoinbase.doOnSiteCheckout();
|
17
|
+
return false;
|
18
|
+
} else {
|
19
|
+
return true;
|
20
|
+
}
|
21
|
+
});
|
22
|
+
})
|
23
|
+
|
24
|
+
window.addEventListener('message', receiveMessage, false);
|
25
|
+
|
26
|
+
// Listen for messages from the on-site payment iframe
|
27
|
+
function receiveMessage(event) {
|
28
|
+
|
29
|
+
if (event.origin == 'https://coinbase.com') {
|
30
|
+
var event_type = event.data.split('|')[0];
|
31
|
+
if (event_type == 'coinbase_payment_complete') {
|
32
|
+
|
33
|
+
// Redirect to success url (wait 1 second for callback to arrive)
|
34
|
+
setTimeout(function() {
|
35
|
+
window.location = SpreeCoinbase.successUrl;
|
36
|
+
}, 1000);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
|
3
|
+
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
4
|
+
d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
|
5
|
+
b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
|
6
|
+
EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
|
7
|
+
cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
|
8
|
+
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
|
9
|
+
JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
|
10
|
+
mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
|
11
|
+
wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
|
12
|
+
VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
|
13
|
+
AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
|
14
|
+
AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
|
15
|
+
BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
|
16
|
+
pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
|
17
|
+
dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
|
18
|
+
fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
|
19
|
+
NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
|
20
|
+
H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
|
21
|
+
+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
|
22
|
+
-----END CERTIFICATE-----
|
23
|
+
-----BEGIN CERTIFICATE-----
|
24
|
+
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
|
25
|
+
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
|
26
|
+
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
|
27
|
+
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
|
28
|
+
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
|
29
|
+
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
|
30
|
+
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
|
31
|
+
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
|
32
|
+
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
|
33
|
+
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
|
34
|
+
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
|
35
|
+
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
|
36
|
+
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
|
37
|
+
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
|
38
|
+
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
|
39
|
+
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
|
40
|
+
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
|
41
|
+
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
|
42
|
+
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
|
43
|
+
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
|
44
|
+
-----END CERTIFICATE-----
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Spree
|
2
|
+
CheckoutController.class_eval do
|
3
|
+
before_filter :coinbase_redirect, :only => [:update]
|
4
|
+
|
5
|
+
private
|
6
|
+
def coinbase_redirect
|
7
|
+
return unless (params[:state] == "payment") && params[:order][:payments_attributes]
|
8
|
+
|
9
|
+
payment_method = PaymentMethod.find(params[:order][:payments_attributes].first[:payment_method_id])
|
10
|
+
if payment_method.kind_of?(Spree::PaymentMethod::Coinbase)
|
11
|
+
redirect_to spree_coinbase_redirect_url(:payment_method_id => payment_method.id)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
class CoinbaseController < StoreController
|
5
|
+
include HTTParty
|
6
|
+
ssl_ca_file File.expand_path(File.join(File.dirname(__FILE__), 'ca-coinbase.crt'))
|
7
|
+
skip_before_filter :verify_authenticity_token
|
8
|
+
|
9
|
+
def redirect
|
10
|
+
order = current_order || raise(ActiveRecord::RecordNotFound)
|
11
|
+
|
12
|
+
if order.state != "payment"
|
13
|
+
redirect_to root_url() # Order is not ready for payment / has already been paid
|
14
|
+
return
|
15
|
+
end
|
16
|
+
|
17
|
+
# Create Coinbase button code
|
18
|
+
secret_token = SecureRandom.base64(30)
|
19
|
+
button_params = { :button => {
|
20
|
+
:name => "Order #%s" % order.number,
|
21
|
+
:price_string => order.total,
|
22
|
+
:price_currency_iso => order.currency,
|
23
|
+
:custom => order.id,
|
24
|
+
:custom_secure => true,
|
25
|
+
:callback_url => spree_coinbase_callback_url(:payment_method_id => params[:payment_method_id], :secret_token => secret_token),
|
26
|
+
:cancel_url => spree_coinbase_cancel_url(:payment_method_id => params[:payment_method_id]),
|
27
|
+
:success_url => spree_coinbase_success_url(:payment_method_id => params[:payment_method_id], :order_num => order.number),
|
28
|
+
:info_url => root_url(),
|
29
|
+
} }
|
30
|
+
result = make_coinbase_request :post, "/buttons", button_params
|
31
|
+
code = result["button"]["code"]
|
32
|
+
|
33
|
+
if code
|
34
|
+
# Add a "processing" payment that is used to verify the callback
|
35
|
+
transaction = CoinbaseTransaction.new
|
36
|
+
transaction.button_id = code
|
37
|
+
transaction.secret_token = secret_token
|
38
|
+
payment = order.payments.create({:amount => order.total,
|
39
|
+
:source => transaction,
|
40
|
+
:payment_method => payment_method })
|
41
|
+
payment.started_processing!
|
42
|
+
|
43
|
+
use_off_site = payment_method.preferred_use_off_site_payment_page
|
44
|
+
redirect_to "https://coinbase.com/%1$s/%2$s" % [use_off_site ? "checkouts" : "inline_payments", code]
|
45
|
+
else
|
46
|
+
redirect_to edit_order_checkout_url(order, :state => 'payment'),
|
47
|
+
:notice => Spree.t(:spree_coinbase_checkout_error)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def callback
|
52
|
+
|
53
|
+
# Download order information from Coinbase (do not trust sent order information)
|
54
|
+
cb_order_id = params["order"]["id"]
|
55
|
+
cb_order = make_coinbase_request :get, "/orders/%s" % cb_order_id, {}
|
56
|
+
|
57
|
+
if cb_order.nil?
|
58
|
+
render text: "Invalid order ID", status: 400
|
59
|
+
return
|
60
|
+
end
|
61
|
+
|
62
|
+
cb_order = cb_order["order"]
|
63
|
+
|
64
|
+
if cb_order["status"] != "completed"
|
65
|
+
render text: "Invalid order status", status: 400
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
# Fetch Spree order information, find relevant payment, and verify button_id
|
70
|
+
order_id = cb_order["custom"]
|
71
|
+
order = Spree::Order.find(order_id)
|
72
|
+
button_id = cb_order["button"]["id"]
|
73
|
+
payments = order.payments.where(:state => "processing",
|
74
|
+
:payment_method_id => payment_method)
|
75
|
+
payment = nil
|
76
|
+
payments.each do |p|
|
77
|
+
if p.source.button_id == button_id
|
78
|
+
payment = p
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if payment.nil?
|
83
|
+
render text: "No matching payment for order", status: 400
|
84
|
+
return
|
85
|
+
end
|
86
|
+
|
87
|
+
# Verify secret_token
|
88
|
+
if payment.source.secret_token != params[:secret_token]
|
89
|
+
render text: "Invalid secret token", status: 400
|
90
|
+
return
|
91
|
+
end
|
92
|
+
|
93
|
+
# Now that this callback has been verified, process the payment!
|
94
|
+
transaction = payment.source
|
95
|
+
transaction.order_id = cb_order_id
|
96
|
+
transaction.save
|
97
|
+
|
98
|
+
# Make payment pending -> make order complete -> make payment complete -> update order
|
99
|
+
payment.pend!
|
100
|
+
order.next
|
101
|
+
if !order.complete?
|
102
|
+
render text: "Could not transition order: %s" % order.errors
|
103
|
+
return
|
104
|
+
end
|
105
|
+
payment.complete!
|
106
|
+
order.update!
|
107
|
+
|
108
|
+
# Successful payment!
|
109
|
+
render text: "Callback successful"
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
def cancel
|
114
|
+
|
115
|
+
order = current_order || raise(ActiveRecord::RecordNotFound)
|
116
|
+
|
117
|
+
# Void the 'pending' payment created in redirect
|
118
|
+
# If doing an on-site checkout params will be nil, so just
|
119
|
+
# cancel all Coinbase payments (it is unlikely there will be more than one)
|
120
|
+
button_id = params["order"]["button"]["id"] rescue nil
|
121
|
+
payments = order.payments.where(:state => "pending",
|
122
|
+
:payment_method_id => payment_method)
|
123
|
+
payments.each do |payment|
|
124
|
+
if payment.source.button_id == button_id || button_id.nil?
|
125
|
+
payment.void!
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
redirect_to edit_order_checkout_url(order, :state => 'payment'),
|
130
|
+
:notice => Spree.t(:spree_coinbase_checkout_cancelled)
|
131
|
+
end
|
132
|
+
|
133
|
+
def success
|
134
|
+
|
135
|
+
order = Spree::Order.find_by_number(params[:order_num]) || raise(ActiveRecord::RecordNotFound)
|
136
|
+
|
137
|
+
if order.complete?
|
138
|
+
session[:order_id] = nil # Reset cart
|
139
|
+
redirect_to spree.order_path(order), :notice => Spree.t(:order_processed_successfully)
|
140
|
+
end
|
141
|
+
|
142
|
+
# If order not complete, wait for callback to come in... (page will automatically refresh, see view)
|
143
|
+
end
|
144
|
+
|
145
|
+
private
|
146
|
+
|
147
|
+
def payment_method
|
148
|
+
m = Spree::PaymentMethod.find(params[:payment_method_id])
|
149
|
+
if !(m.is_a? Spree::PaymentMethod::Coinbase)
|
150
|
+
raise "Invalid payment_method_id"
|
151
|
+
end
|
152
|
+
m
|
153
|
+
end
|
154
|
+
|
155
|
+
# the coinbase-ruby gem is not used because of its dependence on incompatible versions of the money gem
|
156
|
+
def make_coinbase_request verb, path, options
|
157
|
+
|
158
|
+
key = payment_method.preferred_api_key
|
159
|
+
secret = payment_method.preferred_api_secret
|
160
|
+
|
161
|
+
if key.nil? || secret.nil?
|
162
|
+
raise "Please enter an API key and secret in Spree payment method settings"
|
163
|
+
end
|
164
|
+
|
165
|
+
base_uri = "https://coinbase.com/api/v1"
|
166
|
+
nonce = (Time.now.to_f * 1e6).to_i
|
167
|
+
message = nonce.to_s + base_uri + path + options.to_json
|
168
|
+
signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('sha256'), secret, message)
|
169
|
+
|
170
|
+
headers = {
|
171
|
+
'ACCESS_KEY' => key,
|
172
|
+
'ACCESS_SIGNATURE' => signature,
|
173
|
+
'ACCESS_NONCE' => nonce.to_s,
|
174
|
+
"Content-Type" => "application/json",
|
175
|
+
}
|
176
|
+
|
177
|
+
r = self.class.send(verb, base_uri + path, {headers: headers, body: options.to_json})
|
178
|
+
JSON.parse(r.body)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Spree
|
2
|
+
class PaymentMethod::Coinbase < PaymentMethod
|
3
|
+
preference :api_key, :string
|
4
|
+
preference :api_secret, :string
|
5
|
+
preference :use_off_site_payment_page, :boolean
|
6
|
+
|
7
|
+
def auto_capture?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def provider_class
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def payment_source_class
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def source_required?
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
Pay with bitcoin, a digital currency. Payment instructions will be displayed after you click 'Save and Continue'.
|
2
|
+
<script type="text/javascript">
|
3
|
+
SpreeCoinbase.paymentMethodId = <%= payment_method.id %>;
|
4
|
+
SpreeCoinbase.useOffSite = <%= payment_method.preferred_use_off_site_payment_page == true %>;
|
5
|
+
SpreeCoinbase.checkoutUrl = "<%= j spree_coinbase_redirect_url(:payment_method_id => payment_method.id).html_safe %>";
|
6
|
+
SpreeCoinbase.cancelUrl = "<%= j spree_coinbase_cancel_url(:payment_method_id => payment_method.id).html_safe %>";
|
7
|
+
SpreeCoinbase.successUrl = "<%= j spree_coinbase_success_url(:payment_method_id => payment_method.id, :order_num => current_order.number).html_safe %>";
|
8
|
+
</script>
|
data/bin/rails
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
2
|
+
|
3
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
4
|
+
ENGINE_PATH = File.expand_path('../../lib/spree_coinbase/engine', __FILE__)
|
5
|
+
|
6
|
+
require 'rails/all'
|
7
|
+
require 'rails/engine/commands'
|
data/config/routes.rb
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
Spree::Core::Engine.routes.draw do
|
2
|
+
get '/spree_coinbase/redirect', :to => "coinbase#redirect", :as => :spree_coinbase_redirect
|
3
|
+
post '/spree_coinbase/callback', :to => "coinbase#callback", :as => :spree_coinbase_callback
|
4
|
+
get '/spree_coinbase/cancel', :to => "coinbase#cancel", :as => :spree_coinbase_cancel
|
5
|
+
get '/spree_coinbase/success', :to => "coinbase#success", :as => :spree_coinbase_success
|
6
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SpreeCoinbase
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
class_option :auto_run_migrations, :type => :boolean, :default => false
|
6
|
+
|
7
|
+
def add_javascripts
|
8
|
+
append_file 'vendor/assets/javascripts/spree/frontend/all.js', "//= require spree/frontend/spree_coinbase\n"
|
9
|
+
append_file 'vendor/assets/javascripts/spree/backend/all.js', "//= require spree/backend/spree_coinbase\n"
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_stylesheets
|
13
|
+
inject_into_file 'vendor/assets/stylesheets/spree/frontend/all.css', " *= require spree/frontend/spree_coinbase\n", :before => /\*\//, :verbose => true
|
14
|
+
inject_into_file 'vendor/assets/stylesheets/spree/backend/all.css', " *= require spree/backend/spree_coinbase\n", :before => /\*\//, :verbose => true
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_migrations
|
18
|
+
run 'bundle exec rake railties:install:migrations FROM=spree_coinbase'
|
19
|
+
end
|
20
|
+
|
21
|
+
def run_migrations
|
22
|
+
run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask 'Would you like to run the migrations now? [Y/n]')
|
23
|
+
if run_migrations
|
24
|
+
run 'bundle exec rake db:migrate'
|
25
|
+
else
|
26
|
+
puts 'Skipping rake db:migrate, don\'t forget to run it!'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SpreeCoinbase
|
2
|
+
class Engine < Rails::Engine
|
3
|
+
engine_name 'spree_coinbase'
|
4
|
+
|
5
|
+
config.to_prepare do
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__), "../../app/**/*_decorator*.rb")) do |c|
|
7
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
initializer "spree.spree_coinbase.payment_methods", :after => "spree.register.payment_methods" do |app|
|
12
|
+
app.config.spree.payment_methods << Spree::PaymentMethod::Coinbase
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.platform = Gem::Platform::RUBY
|
4
|
+
s.name = 'spree_coinbase'
|
5
|
+
s.version = '2.2.0.1'
|
6
|
+
s.summary = 'Accept bitcoin payments on Spree with Coinbase.'
|
7
|
+
s.description = 'Accept bitcoin payments on your Spree store with Coinbase.'
|
8
|
+
s.required_ruby_version = '>= 1.9.3'
|
9
|
+
|
10
|
+
s.author = 'Coinbase'
|
11
|
+
s.email = 'merchants@coinbase.com'
|
12
|
+
s.homepage = 'https://coinbase.com'
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
#s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.require_path = 'lib'
|
17
|
+
s.requirements << 'none'
|
18
|
+
|
19
|
+
s.add_dependency 'spree_core', '~> 2.2.0'
|
20
|
+
|
21
|
+
s.add_development_dependency 'capybara', '~> 2.1'
|
22
|
+
s.add_development_dependency 'coffee-rails'
|
23
|
+
s.add_development_dependency 'database_cleaner'
|
24
|
+
s.add_development_dependency 'factory_girl', '~> 4.2'
|
25
|
+
s.add_development_dependency 'ffaker'
|
26
|
+
s.add_development_dependency 'rspec-rails', '~> 2.13'
|
27
|
+
s.add_development_dependency 'sass-rails'
|
28
|
+
s.add_development_dependency 'selenium-webdriver'
|
29
|
+
s.add_development_dependency 'simplecov'
|
30
|
+
s.add_development_dependency 'sqlite3'
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,223 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spree_coinbase
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.2.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Coinbase
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: spree_core
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: capybara
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.1'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: coffee-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: database_cleaner
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: factory_girl
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: ffaker
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec-rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '2.13'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '2.13'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: sass-rails
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: selenium-webdriver
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: simplecov
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: sqlite3
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ! '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description: Accept bitcoin payments on your Spree store with Coinbase.
|
168
|
+
email: merchants@coinbase.com
|
169
|
+
executables: []
|
170
|
+
extensions: []
|
171
|
+
extra_rdoc_files: []
|
172
|
+
files:
|
173
|
+
- .gitignore
|
174
|
+
- .rspec
|
175
|
+
- Gemfile
|
176
|
+
- LICENSE
|
177
|
+
- README.md
|
178
|
+
- Rakefile
|
179
|
+
- app/assets/javascripts/spree/backend/spree_coinbase.js
|
180
|
+
- app/assets/javascripts/spree/frontend/spree_coinbase.js
|
181
|
+
- app/assets/stylesheets/spree/backend/spree_coinbase.css
|
182
|
+
- app/assets/stylesheets/spree/frontend/spree_coinbase.css
|
183
|
+
- app/controllers/spree/ca-coinbase.crt
|
184
|
+
- app/controllers/spree/checkout_controller_decorator.rb
|
185
|
+
- app/controllers/spree/coinbase_controller.rb
|
186
|
+
- app/models/spree/coinbase_transaction.rb
|
187
|
+
- app/models/spree/payment_method/coinbase.rb
|
188
|
+
- app/views/spree/admin/payments/source_views/_coinbase.html.erb
|
189
|
+
- app/views/spree/checkout/payment/_coinbase.html.erb
|
190
|
+
- app/views/spree/coinbase/success.html.erb
|
191
|
+
- bin/rails
|
192
|
+
- config/locales/en.yml
|
193
|
+
- config/routes.rb
|
194
|
+
- db/migrate/20140330235546_create_spree_coinbase_transactions.rb
|
195
|
+
- lib/generators/spree_coinbase/install/install_generator.rb
|
196
|
+
- lib/spree_coinbase.rb
|
197
|
+
- lib/spree_coinbase/engine.rb
|
198
|
+
- spree_coinbase.gemspec
|
199
|
+
homepage: https://coinbase.com
|
200
|
+
licenses: []
|
201
|
+
metadata: {}
|
202
|
+
post_install_message:
|
203
|
+
rdoc_options: []
|
204
|
+
require_paths:
|
205
|
+
- lib
|
206
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - ! '>='
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: 1.9.3
|
211
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ! '>='
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
requirements:
|
217
|
+
- none
|
218
|
+
rubyforge_project:
|
219
|
+
rubygems_version: 2.2.2
|
220
|
+
signing_key:
|
221
|
+
specification_version: 4
|
222
|
+
summary: Accept bitcoin payments on Spree with Coinbase.
|
223
|
+
test_files: []
|