Skip to content

Commit 18e763d

Browse files
committed
Allow donate app to use Stripe Checkout for one-time donations
Extend Gold Stripe Checkout code to support one-time donations from `readthedocs-ext`.
1 parent 3ea85d3 commit 18e763d

File tree

5 files changed

+39
-28
lines changed

5 files changed

+39
-28
lines changed

media/css/core.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ form p label { font-weight: normal; }
104104
form p.required label { font-weight: bold; }
105105
textarea, input, button, .button, select { display: block; padding: 5px; color: #444; background-color: #fff; border: 1px solid #BFBFBF; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; }
106106
textarea, input, .button { box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.5) inset; -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.5) inset; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.5) inset; }
107-
input[type="text"], input[type="password"] { width: 250px; height: 20px; margin-bottom: 5px; background: #fff; }
107+
input[type="text"], input[type="password"], input[type="email"] { width: 250px; height: 20px; margin-bottom: 5px; background: #fff; }
108108
input::-webkit-input-placeholder { color: #ccc; }
109109
input:-moz-placeholder { color: #ccc; opacity: 1; }
110110
input::-moz-placeholder { color: #ccc; opacity: 1; }

readthedocs/gold/static-src/gold/js/checkout.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ function StripeCheckoutView(config) {
1515
// Avoid submitting the form
1616
event.preventDefault();
1717

18-
var priceId = document.getElementById(self.levelId).value;
19-
self.createCheckoutSession(priceId).then(function (result) {
18+
self.createCheckoutSession().then(function (result) {
2019
// Call Stripe.js method to redirect to the new Checkout page
2120
result.json().then(function (data) {
2221
self.stripe
@@ -28,15 +27,28 @@ function StripeCheckoutView(config) {
2827
});
2928
};
3029

31-
self.createCheckoutSession = function (priceId) {
30+
self.createCheckoutSession = function () {
31+
var priceId = document.getElementById(self.levelId).value;
32+
// One-time donation fields
33+
var name = document.getElementById('id_name').value;
34+
var email = document.getElementById('id_email').value;
35+
var logoUrl = document.getElementById('id_logo_url').value;
36+
var siteUrl = document.getElementById('id_site_url').value;
37+
var public = document.getElementById('id_public').checked;
38+
3239
return fetch(self.checkoutSessionUrl, {
3340
method: "POST",
3441
headers: {
3542
"Content-Type": "application/json",
3643
"X-CSRFToken": self.csrfToken
3744
},
3845
body: JSON.stringify({
39-
priceId: priceId
46+
priceId: priceId,
47+
name: name,
48+
email: email,
49+
logoUrl: logoUrl,
50+
siteUrl: siteUrl,
51+
public: public,
4052
})
4153
});
4254
};

readthedocs/gold/static/gold/js/checkout.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

readthedocs/gold/views.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,15 +226,27 @@ def post(self, request, format=None):
226226

227227
if event.type == self.EVENT_CHECKOUT_COMPLETED:
228228
username = event.data.object.client_reference_id
229-
subscription = stripe.Subscription.retrieve(event.data.object.subscription)
230-
231-
user = User.objects.get(username=username)
232-
GoldUser.objects.create(
233-
user=user,
234-
level=subscription.plan.id,
235-
stripe_id=stripe_customer,
236-
subscribed=True,
237-
)
229+
mode = event.data.object.mode
230+
if mode == 'subscription':
231+
# Gold Membership
232+
user = User.objects.get(username=username)
233+
subscription = stripe.Subscription.retrieve(event.data.object.subscription)
234+
GoldUser.objects.create(
235+
user=user,
236+
level=subscription.plan.id,
237+
stripe_id=stripe_customer,
238+
subscribed=True,
239+
)
240+
elif mode == 'payment':
241+
# One-time donation
242+
try:
243+
# TODO: find a better way to extend this view for one-time donations.
244+
from readthedocsext.donate.utils import handle_payment_webhook
245+
stripe_session = event.data.object.id
246+
price = event.data.object.amount_total
247+
handle_payment_webhook(username, stripe_customer, stripe_session, price)
248+
except ImportError:
249+
log.warning('Not able to import handle_payment_webhook for one-time donation.')
238250
# TODO: add user notification saying it was successful
239251

240252
elif event.type == self.EVENT_CHECKOUT_PAYMENT_FAILED:

readthedocs/payments/mixins.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,3 @@ def get_context_data(self, **kwargs):
1313
context = super().get_context_data(**kwargs)
1414
context['stripe_publishable'] = settings.STRIPE_PUBLISHABLE
1515
return context
16-
17-
def get_form(self, data=None, files=None, **kwargs):
18-
"""
19-
Pass in copy of POST data to avoid read only QueryDicts on form.
20-
21-
This is used to be able to reset some important credit card fields if
22-
card validation fails. In this case, the Stripe token was valid, but the
23-
card was rejected during the charge or subscription instantiation.
24-
"""
25-
if self.request.method == 'POST':
26-
data = self.request.POST.copy()
27-
cls = self.get_form_class()
28-
return cls(data=data, files=files, **kwargs)

0 commit comments

Comments
 (0)