Skip to content

Add a way for sponsors to pay without asking for logos etc. #2503

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Mar 3, 2017
Merged
44 changes: 44 additions & 0 deletions readthedocs/donate/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,47 @@ def save(self, commit=True):
supporter.user = self.user
supporter.save()
return supporter


class EthicalAdForm(StripeResourceMixin, StripeModelForm):

"""Payment form for ethical ads

This extends the basic payment form, giving fields for credit card number,
expiry, and CVV. The proper Knockout data bindings are established on
:py:class:`StripeModelForm`
"""

class Meta:
model = Supporter
fields = (
'last_4_digits',
'name',
'email',
'dollars',
)
help_texts = {
'email': _('Your email is used so we can send you a receipt'),
}
widgets = {
'dollars': forms.HiddenInput(attrs={
'data-bind': 'value: dollars'
}),
'last_4_digits': forms.TextInput(attrs={
'data-bind': 'valueInit: card_digits, value: card_digits'
}),
}

last_4_digits = forms.CharField(widget=forms.HiddenInput(), required=True)
name = forms.CharField(required=True)
email = forms.CharField(required=True)

def validate_stripe(self):
"""Call stripe for payment (not ideal here) and clean up logo < $200"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copypasta docstring

stripe.Charge.create(
amount=int(self.cleaned_data['dollars']) * 100,
currency='usd',
source=self.cleaned_data['stripe_token'],
description='Read the Docs Ethical Ads',
receipt_email=self.cleaned_data['email']
)
15 changes: 15 additions & 0 deletions readthedocs/donate/templates/donate/ethicalads-success.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{% extends "base.html" %}

{% load i18n %}
{% load static %}

{% block title %}{% trans "Sustainability" %}{% endblock %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Title should mention advertising


{% block content %}
<h2>Thanks for your support</h2>

<p>
We appreciate your contribution greatly, thank you for showing your support!
Your help will go a long ways towards making the service more sustainable.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should instead mention buying an ad, marketing departments aren't donating to us to make us more sustainable.

</p>
{% endblock %}
91 changes: 91 additions & 0 deletions readthedocs/donate/templates/donate/ethicalads.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{% extends "base.html" %}

{% load i18n %}
{% load static %}

{% block title %}{% trans "Pay for your ad" %}{% endblock %}

{% block extra_links %}
<link rel="stylesheet" href="{% static 'payments/css/form.css' %}" />
{% endblock %}

{% block extra_scripts %}
<script src="https://js.stripe.com/v2/" type="text/javascript"></script>
<script type="text/javascript" src="{% static 'vendor/knockout.js' %}"></script>
<script type="text/javascript" src="{% static 'donate/js/donate.js' %}"></script>
<script type="text/javascript">
var donate_views = require('donate/donate');
$(document).ready(function () {
var key;
//<![CDATA[
key = '{{ stripe_publishable }}';
//]]>

var view = donate_views.DonateView.init({
key: key,
form: $('form#donate-payment')
});
});
</script>
{% endblock %}


{% block content %}
<h2>Pay for your Sponsorship</h2>

<p>
This form can be used to pay for your sponsorship of Read the Docs.
Thanks for helping make Open Source more sustainable!
</p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same with the title and this paragraph block. Framing this as sponsorship is misleading.


<form action="" method="post" id="donate-payment" class="payment">
{% csrf_token %}

{{ form.non_field_errors }}

{% for field in form.fields_with_cc_group %}
{% if field.is_cc_group %}
<div class="subscription-card">
{% for groupfield in field.fields %}
{% include 'core/ko_form_field.html' with field=groupfield %}
{% endfor %}
</div>
{% elif field.name == 'dollars' %}
{{ field.errors }}
<p>
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
<input
type="hidden"
name="{{ field.name }}"
id="{{ field.id_for_label }}"
data-bind="value: dollars" />
<input
type="number"
data-bind="textInput: dollars_input, visible: dollars_select() == 'custom'"
value="50"
id="id_dollars_input"
style="display: none;" />
<select data-bind="value: dollars_select, visible: dollars_select() != 'custom'">
<option value="custom">{% trans "Custom amount" %}</option>
<option value="2000">$2,000</option>
<option value="3000">$3,000</option>
<option value="5000" selected>$5,000</option>
<option value="10000">$10,000</option>
</select>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This select shouldn't exist at all.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left this to set the standard expectation that they should be paying us $5k test buys. Seemed simpler to have this select than rewrite how we were handling the actual data.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does seem a bit odd still though. Altering the form should be straight forward. You'd need to remove the <select>, drop the visible data bind parameter on <input>, and drop the style parameter on the <input> as well. This should give a permanent text input.

{% if field.help_text %}
<span class="helptext">{{ field.help_text }}</span>
{% endif %}
</p>
{% else %}
{% include 'core/ko_form_field.html' with field=field %}
{% endif %}
{% endfor %}

{% trans "Pay" as form_submit_text %}
<input type="submit" value="{{ form_submit_text }}" data-bind="click: process_form" />
<p>
We do not store your credit card details,
payment is processed directly through <a href="https://stripe.com">Stripe</a>.
</p>
</form>
{% endblock %}
7 changes: 4 additions & 3 deletions readthedocs/donate/urls.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
from django.conf.urls import url, include

from .views import DonateCreateView
from .views import DonateListView
from .views import DonateSuccessView
from .views import DonateCreateView, DonateListView, DonateSuccessView
from .views import PayAdsView, PaySuccess
from .views import click_proxy, view_proxy


urlpatterns = [
url(r'^$', DonateListView.as_view(), name='donate'),
url(r'^pay/$', PayAdsView.as_view(), name='pay_ads'),
url(r'^pay/success/$', PaySuccess.as_view(), name='pay_success'),
url(r'^contribute/$', DonateCreateView.as_view(), name='donate_add'),
url(r'^contribute/thanks$', DonateSuccessView.as_view(), name='donate_success'),
url(r'^view/(?P<promo_id>\d+)/(?P<hash>.+)/$', view_proxy, name='donate_view_proxy'),
Expand Down
18 changes: 17 additions & 1 deletion readthedocs/donate/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,28 @@
from readthedocs.projects.models import Project

from .models import Supporter, SupporterPromo, CLICKS, VIEWS
from .forms import SupporterForm
from .forms import SupporterForm, EthicalAdForm
from .mixins import DonateProgressMixin

log = logging.getLogger(__name__)


class PayAdsView(StripeMixin, CreateView):

"""Create a donation locally and in Stripe"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/donation/advertising payment/


form_class = EthicalAdForm
success_message = _('Your payment has been received')
template_name = 'donate/ethicalads.html'

def get_success_url(self):
return reverse('pay_success')


class PaySuccess(TemplateView):
template_name = 'donate/ethicalads-success.html'


class DonateCreateView(StripeMixin, CreateView):

"""Create a donation locally and in Stripe"""
Expand Down