mirror of https://gitlab.com/tildes/tildes.git
Browse Source
Remove ability to accept donations via Stripe
Remove ability to accept donations via Stripe
All of the Stripe payments have been fraud for months now, it's not worth continuing to deal with the refunds and chargebacks.merge-requests/135/head
Deimos
2 years ago
10 changed files with 0 additions and 253 deletions
-
4tildes/production.ini.example
-
1tildes/requirements.in
-
10tildes/static/js/behaviors/stripe-checkout.js
-
28tildes/static/js/behaviors/stripe-donate-form.js
-
4tildes/tildes/lib/ratelimit.py
-
4tildes/tildes/routes.py
-
54tildes/tildes/templates/donate_stripe.jinja2
-
18tildes/tildes/templates/donate_stripe_redirect.jinja2
-
15tildes/tildes/templates/donate_success.jinja2
-
115tildes/tildes/views/donate.py
@ -1,10 +0,0 @@ |
|||
// Copyright (c) 2019 Tildes contributors <code@tildes.net>
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|||
|
|||
$.onmount("[data-js-stripe-checkout]", function() { |
|||
/* eslint-disable-next-line no-undef */ |
|||
var stripe = Stripe($(this).attr("data-js-stripe-checkout")); |
|||
stripe.redirectToCheckout({ |
|||
sessionId: $(this).attr("data-js-stripe-checkout-session") |
|||
}); |
|||
}); |
@ -1,28 +0,0 @@ |
|||
// Copyright (c) 2019 Tildes contributors <code@tildes.net>
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|||
|
|||
$.onmount("[data-js-stripe-donate-form]", function() { |
|||
$(this).on("submit", function(event) { |
|||
var $amountInput = $(this).find("#amount"); |
|||
var amount = $amountInput.val(); |
|||
|
|||
var $errorDiv = $(this).find(".text-status-message"); |
|||
|
|||
// remove dollar sign and/or comma, then parse into float
|
|||
amount = amount.replace(/[$,]/g, ""); |
|||
amount = parseFloat(amount); |
|||
|
|||
if (isNaN(amount)) { |
|||
$errorDiv.text("Please enter a valid dollar amount."); |
|||
event.preventDefault(); |
|||
return; |
|||
} else if (amount < 1.0) { |
|||
$errorDiv.text("Donation amount must be at least $1."); |
|||
event.preventDefault(); |
|||
return; |
|||
} |
|||
|
|||
// set the value in case any of the replacements happened
|
|||
$amountInput.val(amount); |
|||
}); |
|||
}); |
@ -1,54 +0,0 @@ |
|||
{# Copyright (c) 2019 Tildes contributors <code@tildes.net> #} |
|||
{# SPDX-License-Identifier: AGPL-3.0-or-later #} |
|||
|
|||
{% extends 'base_no_sidebar.jinja2' %} |
|||
|
|||
{% block title %}Donate to Tildes{% endblock %} |
|||
|
|||
{% block main_heading %}Credit card donation (via Stripe){% endblock %} |
|||
|
|||
{% block content %} |
|||
<p>After submitting this form, you will be redirected to the Stripe site to enter your payment info.</p> |
|||
|
|||
<p>Note that the donation is in Canadian Dollars (CAD) by default, but you can switch to USD if you prefer. At the moment, $10 CAD is about $7.50 USD.</p> |
|||
|
|||
<div class="divider"></div> |
|||
|
|||
<form class="form-narrow" method="post" data-js-stripe-donate-form> |
|||
<input type="hidden" name="csrf_token" value="{{ get_csrf_token() }}"> |
|||
|
|||
<div class="form-group"> |
|||
<label class="form-label">Donation type</label> |
|||
<label class="form-radio"> |
|||
<input type="radio" name="interval" value="onetime" checked> |
|||
<i class="form-icon"></i> One time |
|||
</label> |
|||
<label class="form-radio"> |
|||
<input type="radio" name="interval" value="month"> |
|||
<i class="form-icon"></i> Monthly |
|||
</label> |
|||
<label class="form-radio"> |
|||
<input type="radio" name="interval" value="year"> |
|||
<i class="form-icon"></i> Yearly |
|||
</label> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label class="form-label" for="amount">Donation amount (must be at least $1)</label> |
|||
|
|||
<div class="input-group"> |
|||
<span class="input-group-addon">$</span> |
|||
<input class="form-input" id="amount" name="amount" type="text" data-js-auto-focus> |
|||
<select class="form-select" id="currency" name="currency"> |
|||
<option value="CAD" selected>CAD</option> |
|||
<option value="USD">USD</option> |
|||
</select> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-buttons"> |
|||
<button class="btn btn-primary" type="submit">Donate</button> |
|||
<div class="text-status-message text-error"></div> |
|||
</div> |
|||
</form> |
|||
{% endblock %} |
@ -1,18 +0,0 @@ |
|||
{# Copyright (c) 2018 Tildes contributors <code@tildes.net> #} |
|||
{# SPDX-License-Identifier: AGPL-3.0-or-later #} |
|||
|
|||
{% extends 'base_no_sidebar.jinja2' %} |
|||
|
|||
{% block title %}Stripe donation{% endblock %} |
|||
|
|||
{% block content %} |
|||
<script src="https://js.stripe.com/v3/"></script> |
|||
|
|||
<p>Redirecting to Stripe...</p> |
|||
|
|||
{# This div will cause the page to redirect to the Stripe Checkout page #} |
|||
<div |
|||
data-js-stripe-checkout="{{ publishable_key }}" |
|||
data-js-stripe-checkout-session="{{ session_id }}" |
|||
></div> |
|||
{% endblock %} |
@ -1,15 +0,0 @@ |
|||
{# Copyright (c) 2019 Tildes contributors <code@tildes.net> #} |
|||
{# SPDX-License-Identifier: AGPL-3.0-or-later #} |
|||
|
|||
{% extends 'base_no_sidebar.jinja2' %} |
|||
|
|||
{% block title %}Thanks for donating!{% endblock %} |
|||
|
|||
{% block content %} |
|||
<div class="empty"> |
|||
<h2 class="empty-title">Thanks for donating to Tildes!</h2> |
|||
<p class="empty-subtitle">You should receive an email receipt. If you have any questions, please feel free to contact <a href="mailto:donate@tildes.net">donate@tildes.net</a></p> |
|||
|
|||
<div class="empty-action"><a href="/" class="btn btn-primary">Back to the home page</a></div> |
|||
</div> |
|||
{% endblock %} |
@ -1,115 +0,0 @@ |
|||
# Copyright (c) 2018 Tildes contributors <code@tildes.net> |
|||
# SPDX-License-Identifier: AGPL-3.0-or-later |
|||
|
|||
"""The view for donating via Stripe.""" |
|||
|
|||
import stripe |
|||
from marshmallow.fields import Float, String |
|||
from marshmallow.validate import OneOf, Range |
|||
from pyramid.httpexceptions import HTTPInternalServerError |
|||
from pyramid.request import Request |
|||
from pyramid.security import NO_PERMISSION_REQUIRED |
|||
from pyramid.view import view_config |
|||
|
|||
from tildes.metrics import incr_counter |
|||
from tildes.views.decorators import rate_limit_view, use_kwargs |
|||
|
|||
|
|||
@view_config( |
|||
route_name="donate_stripe", |
|||
request_method="GET", |
|||
renderer="donate_stripe.jinja2", |
|||
permission=NO_PERMISSION_REQUIRED, |
|||
) |
|||
def get_donate_stripe(request: Request) -> dict: |
|||
"""Display the form for donating with Stripe.""" |
|||
# pylint: disable=unused-argument |
|||
return {} |
|||
|
|||
|
|||
@view_config( |
|||
route_name="donate_stripe", |
|||
request_method="POST", |
|||
renderer="donate_stripe_redirect.jinja2", |
|||
permission=NO_PERMISSION_REQUIRED, |
|||
) |
|||
@use_kwargs( |
|||
{ |
|||
"amount": Float(required=True, validate=Range(min=1.0)), |
|||
"currency": String(required=True, validate=OneOf(("CAD", "USD"))), |
|||
"interval": String(required=True, validate=OneOf(("onetime", "month", "year"))), |
|||
}, |
|||
location="form", |
|||
) |
|||
@rate_limit_view("global_donate_stripe") |
|||
@rate_limit_view("donate_stripe") |
|||
def post_donate_stripe( |
|||
request: Request, amount: int, currency: str, interval: str |
|||
) -> dict: |
|||
"""Process a Stripe donation.""" |
|||
try: |
|||
stripe.api_key = request.registry.settings["api_keys.stripe.secret"] |
|||
publishable_key = request.registry.settings["api_keys.stripe.publishable"] |
|||
product_id = request.registry.settings["stripe.recurring_donation_product_id"] |
|||
except KeyError as exc: |
|||
raise HTTPInternalServerError from exc |
|||
|
|||
incr_counter("donation_initiations", type="stripe") |
|||
|
|||
if interval == "onetime": |
|||
session = stripe.checkout.Session.create( |
|||
payment_method_types=["card"], |
|||
line_items=[ |
|||
{ |
|||
"name": "One-time donation - tildes.net", |
|||
"amount": int(amount * 100), |
|||
"currency": currency, |
|||
"quantity": 1, |
|||
} |
|||
], |
|||
submit_type="donate", |
|||
success_url="https://tildes.net/donate_success", |
|||
cancel_url="https://docs.tildes.net/donate", |
|||
) |
|||
else: |
|||
product = stripe.Product.retrieve(product_id) |
|||
existing_plans = stripe.Plan.list(product=product, active=True, limit=100) |
|||
|
|||
# look through existing plans to see if there's already a matching one, or |
|||
# create a new plan if not |
|||
for existing_plan in existing_plans: |
|||
if ( |
|||
existing_plan.amount == int(amount * 100) |
|||
and existing_plan.currency == currency.lower() |
|||
and existing_plan.interval == interval |
|||
): |
|||
plan = existing_plan |
|||
break |
|||
else: |
|||
plan = stripe.Plan.create( |
|||
amount=int(amount * 100), |
|||
currency=currency, |
|||
interval=interval, |
|||
product=product, |
|||
) |
|||
|
|||
session = stripe.checkout.Session.create( |
|||
payment_method_types=["card"], |
|||
subscription_data={"items": [{"plan": plan.id}]}, |
|||
success_url="https://tildes.net/donate_success", |
|||
cancel_url="https://docs.tildes.net/donate", |
|||
) |
|||
|
|||
return {"publishable_key": publishable_key, "session_id": session.id} |
|||
|
|||
|
|||
@view_config(route_name="donate_success", renderer="donate_success.jinja2") |
|||
def get_donate_success(request: Request) -> dict: |
|||
"""Display a message after a successful donation.""" |
|||
# pylint: disable=unused-argument |
|||
|
|||
# incrementing this metric on page-load and hard-coding Stripe isn't ideal, but it |
|||
# should do the job for now |
|||
incr_counter("donations", type="stripe") |
|||
|
|||
return {} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue