Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add Stripe Cancellation Webhook (#1682)
  • Loading branch information
jessleenyc authored and maestromac committed Feb 13, 2019
1 parent 7492783 commit 49e3878
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 1 deletion.
1 change: 1 addition & 0 deletions Envfile
Expand Up @@ -130,6 +130,7 @@ variable :SLACK_WEBHOOK_URL, :String, default: "Optional"
# Stripe for payment system
variable :STRIPE_PUBLISHABLE_KEY, :String, default: "Optional"
variable :STRIPE_SECRET_KEY, :String, default: "Optional"
variable :STRIPE_CANCELLATION_SECRET, :String, default: "Optional"

# For browser webpush notifications (webpush gem) (totally random base64 nums)
variable :VAPID_PUBLIC_KEY, :String, default: "dGhpcyBpcyBkZXYudG8gdGVzdCBkYXRh"
Expand Down
39 changes: 39 additions & 0 deletions app/controllers/stripe_cancellations_controller.rb
@@ -0,0 +1,39 @@
class StripeCancellationsController < ApplicationController
skip_before_action :verify_authenticity_token, only: :create

def create
verify_stripe_signature
unsubscribe_customer
end

def verify_stripe_signature
payload = request.body.read
sig_header = request.env["HTTP_STRIPE_SIGNATURE"]

begin
Stripe::Webhook.construct_event(
payload, sig_header, Rails.configuration.stripe[:stripe_cancellation_secret]
)
rescue JSON::ParserError
# Invalid payload
status 400
return
rescue Stripe::SignatureVerificationError
# Invalid signature
status 400
return
end
end

def unsubscribe_customer
event = Stripe::Event.retrieve(params[:id])
stripe_id = event.data.object.customer
customer = Stripe::Customer.retrieve(stripe_id)
monthly_dues = event.data.object.items.data[0].plan.amount
user = User.where(stripe_id_code: stripe_id).first
MembershipService.new(customer, user, monthly_dues).unsubscribe_customer
render body: nil, status: 200
rescue Stripe::APIConnectionError, Stripe::StripeError
render body: nil, status: 400
end
end
2 changes: 2 additions & 0 deletions app/services/membership_service.rb
Expand Up @@ -42,6 +42,8 @@ def create_subscription
end

def cancel_subscription
return true if customer.subscriptions.none?

subscription.delete
end

Expand Down
3 changes: 2 additions & 1 deletion config/initializers/stripe.rb
@@ -1,6 +1,7 @@
Rails.configuration.stripe = {
publishable_key: ApplicationConfig["STRIPE_PUBLISHABLE_KEY"],
secret_key: ApplicationConfig["STRIPE_SECRET_KEY"]
secret_key: ApplicationConfig["STRIPE_SECRET_KEY"],
stripe_cancellation_secret: ApplicationConfig["STRIPE_CANCELLATION_SECRET"]
}

Stripe.api_key = Rails.configuration.stripe[:secret_key]
1 change: 1 addition & 0 deletions config/routes.rb
Expand Up @@ -112,6 +112,7 @@
resources :tags, only: [:index]
resources :stripe_subscriptions, only: %i[create update destroy]
resources :stripe_active_cards, only: %i[create update destroy]
resources :stripe_cancellations, only: [:create]
resources :live_articles, only: [:index]
resources :github_repos, only: %i[create update]
resources :buffered_articles, only: [:index]
Expand Down
32 changes: 32 additions & 0 deletions spec/requests/stripe_cancellations_spec.rb
@@ -0,0 +1,32 @@
require "rails_helper"

RSpec.describe "StripeCancellations", type: :request do
let(:user) { create(:user) }
let(:stripe_helper) { StripeMock.create_test_helper }

before do
StripeMock.start
allow_any_instance_of(StripeCancellationsController).to receive(:verify_stripe_signature).and_return(true)
end

after { StripeMock.stop }

it "mocks a stripe cancellation webhook" do
customer = Stripe::Customer.create(
email: user.email,
source: stripe_helper.generate_card_token,
)
MembershipService.new(customer, user, 12).subscribe_customer
user.reload
expect(user.monthly_dues).not_to eq(0)

event = StripeMock.mock_webhook_event(
"customer.subscription.deleted",
customer: user.stripe_id_code, total_count: 1,
)
post "/stripe_cancellations", params: event.as_json
user.reload
expect(user.monthly_dues).to eq(0)
expect(response).to have_http_status(200)
end
end

0 comments on commit 49e3878

Please sign in to comment.