aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--blog/forms.py9
-rw-r--r--blog/urls.py3
-rw-r--r--blog/views.py64
-rw-r--r--requirements.txt3
-rw-r--r--templates/blog/donate.html63
-rw-r--r--templates/blog/partials/sidebar.html10
-rw-r--r--templates/blog/post.html33
7 files changed, 182 insertions, 3 deletions
diff --git a/blog/forms.py b/blog/forms.py
new file mode 100644
index 00000000..a76e354b
--- /dev/null
+++ b/blog/forms.py
@@ -0,0 +1,9 @@
+from django import forms
+import datetime
+
+class PaymentForm(forms.Form):
+ amount = forms.CharField(required=True, widget=forms.NumberInput, label='Amount')
+ card_number = forms.CharField(max_length=16, min_length=16, required=True, widget=forms.NumberInput, label='Card Number')
+ card_expiry_mm = forms.ChoiceField(choices=[(i, i) for i in range(1, 13)], required=True, label='Expiry Month')
+ card_expiry_yyyy = forms.ChoiceField(choices=[(i, i) for i in range(datetime.datetime.now().year, datetime.datetime.now().year + 21)], required=True, label='Expiry Year')
+ card_cvv = forms.CharField(max_length=3, min_length=3, required=True, widget=forms.NumberInput, label='CVV')
diff --git a/blog/urls.py b/blog/urls.py
index 57abe74e..b056b74e 100644
--- a/blog/urls.py
+++ b/blog/urls.py
@@ -13,5 +13,6 @@ urlpatterns = [
path('articles/<str:slug>/comment', views.comment, name='comment'),
path('articles/<str:slug>/edit_comment', views.edit_comment, name='edit_comment'),
path('articles/<str:slug>/delete_comment/<int:comment_id>', views.delete_comment, name='delete_comment'),
- path('users/~<str:username>', views.user_activity, name='user_activity'),
+ path('~<str:username>', views.user_activity, name='user_activity'),
+ path('donate', views.donate, name='donate'),
]
diff --git a/blog/views.py b/blog/views.py
index e3d1e951..d13d7c93 100644
--- a/blog/views.py
+++ b/blog/views.py
@@ -13,7 +13,17 @@ from users.forms import RegisterForm, UpdateUserDetailsForm
from users.tokens import CaptchaTokenGenerator
from django.contrib import messages
from bs4 import BeautifulSoup
+from .forms import PaymentForm
import re
+from dotenv import load_dotenv
+import os
+import stripe
+import requests
+import math
+load_dotenv()
+
+stripe.api_key = os.getenv('STRIPE_SECRET_KEY')
+
def atoi(text):
return int(text) if text.isdigit() else text
@@ -254,4 +264,56 @@ def user_activity(request, username):
comment.body = comment_processor(comment.body)
return render(request, 'blog/activity.html', {'title': 'User Activity', 'activity_user': user, 'activity_user_profile': user_profile, 'activity_recent_comments': recent_comments, 'activity_user_email': user_email})
-
+
+def donate(request):
+ amount = request.GET.get('amount')
+
+ try:
+ amount = int(amount)
+ except:
+ amount = 3
+ amount = amount if amount > 0 else 3
+ amount = amount if amount < 1000 else 1000
+ payment_form = PaymentForm(initial={'amount': amount})
+
+ if request.method == 'POST':
+ try:
+ # create a payment using stripe
+ payment_method = stripe.PaymentMethod.create(
+ type='card',
+ card={
+ 'number': request.POST['card_number'],
+ 'exp_month': request.POST['card_expiry_mm'],
+ 'exp_year': request.POST['card_expiry_yyyy'],
+ 'cvc': request.POST['card_cvv'],
+ },
+ )
+
+ # get the current usd to inr conversion rate
+ rate = requests.get('https://api.exchangerate-api.com/v4/latest/USD').json()['rates']['INR']
+
+ # convert the amount to inr
+ init_amt = int(request.POST['amount'])
+ amount = init_amt * math.ceil(rate) * 100
+ print(amount)
+
+ # create a payment intent
+ payment_intent = stripe.PaymentIntent.create(
+ amount=amount,
+ currency='inr',
+ payment_method_types=['card'],
+ payment_method=payment_method.id,
+ confirm=True,
+ )
+
+ if payment_intent.status == 'succeeded':
+ return redirect(reverse('blog:donate') + '?tab=success&payment_method=' + payment_intent.payment_method_types[0] + '&payment_id=' + payment_intent.id + '&payment_status=' + payment_intent.status + '&payment_created=' + str(payment_intent.created) + '&payment_amount=' + str(int(payment_intent.amount / 100)) + '&payment_currency=' + payment_intent.currency + '&amount=' + str(init_amt))
+ else:
+ return redirect(reverse('blog:donate') + '?tab=error&payment_method=' + payment_intent.payment_method_types[0] + '&payment_id=' + payment_intent.id + '&payment_status=' + payment_intent.status + '&payment_created=' + str(payment_intent.created) + '&payment_amount=' + str(int(payment_intent.amount / 100)) + '&payment_currency=' + payment_intent.currency + '&amount=' + str(init_amt))
+
+ except Exception as e:
+ print(e)
+ return redirect(reverse('blog:donate') + '?tab=error')
+
+ return render(request, 'blog/donate.html', {'title': 'Donate', 'amount': amount, 'payment_form': payment_form})
+
diff --git a/requirements.txt b/requirements.txt
index 16235e50..093d9b23 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,4 +10,5 @@ requests
pillow
pycryptodome
pygments
-bs4 \ No newline at end of file
+bs4
+stripe
diff --git a/templates/blog/donate.html b/templates/blog/donate.html
new file mode 100644
index 00000000..d9004ed8
--- /dev/null
+++ b/templates/blog/donate.html
@@ -0,0 +1,63 @@
+{% extends 'blog/partials/base.html' %} {% block content %}
+{% load static %}
+
+{% if not request.GET.payment_id %}
+<div id="donation">
+ <h2 style="text-transform: none; border: none; padding: 0; font-size: 16px;">
+ {% if request.GET.referrer %}
+ Complete your donation of ${{ amount }}:
+ {% else %}
+ Donate to the blog:
+ {% endif %}
+ </h2>
+ <form method="POST" action="{% url 'blog:donate' %}">
+ {% csrf_token %}
+ <table>
+ {{ payment_form.as_table }}
+ </table>
+ <input type="submit" value="Donate" class="button button-special" />
+ </form>
+</div>
+<div id="fineprint" class="mtsbitem">
+ <h2>Donation Fine Print</h2>
+ <ul>
+ <li>Donations are processed by Stripe, no credit card information is stored on this site.</li>
+ <li>Donations are processed in INR. All conversions will be made according to the latest rates.</li>
+ <li>Donations are non-refundable. If you donate by accident, please contact me and I will refund your donation.</li>
+ </ul>
+</div>
+<div id="testing-info" class="mtsbitem error">
+ <h2>Testing Info</h2>
+ <p>The current payment form is only for testing purposes. It will not actually process a payment. If you would like to test the payment form, please use the following information:</p>
+ <ul>
+ <li>Card Number: 4242 4242 4242 4242</li>
+ <li>Expiration Date: Any date in the future</li>
+ <li>CVV: Any 3 digits</li>
+ </ul>
+</div>
+{% endif %}
+
+{% if request.GET.payment_id and request.GET.payment_status == 'succeeded' %}
+<div id="donation-success" style="width: 400px; margin: 0 auto;">
+ <h1>Thank you for your donation!</h1>
+ <p>Your donation of ${{ request.GET.amount }} has been processed successfully. Thank you for your support! You can find the transaction details below.</p>
+ <p><b>Transaction ID:</b> {{ request.GET.payment_id }}</p>
+ <p><b>Amount:</b> ${{ request.GET.amount }}</p>
+ <p><b>Amount Charged:</b> INR {{ request.GET.payment_amount }}</p>
+ <p><b>Payment Method:</b> <span style="text-transform:uppercase">{{ request.GET.payment_method }}</span></p>
+ <p><b>Payment Status:</b> <span style="text-transform:uppercase">{{ request.GET.payment_status }}</span></p>
+ <a href="{% url 'blog:home' %}" class="button button-special" style="text-decoration: none;">Return to Blog</a>
+</div>
+{% endif %}
+
+{% if request.GET.payment_id and request.GET.payment_status == 'failed' %}
+<div id="donation-failed" style="width: 400px; margin: 0 auto;">
+ <h1>Donation Failed</h1>
+ <p>Your donation of ${{ request.GET.amount }} has failed. You can find the transaction details below.</p>
+ <p><b>Transaction ID:</b> {{ request.GET.payment_id }}</p>
+ <p><b>Amount:</b> ${{ request.GET.amount }}</p>
+ <a href="{% url 'blog:donate' %}?amount={{ amount }}" class="button button-special" style="text-decoration: none;">Try Again</a>
+</div>
+{% endif %}
+
+{% endblock %}
diff --git a/templates/blog/partials/sidebar.html b/templates/blog/partials/sidebar.html
index af31552d..ffe34f7f 100644
--- a/templates/blog/partials/sidebar.html
+++ b/templates/blog/partials/sidebar.html
@@ -145,6 +145,16 @@
</li>
<li>
<span>
+ <img src="{% static 'images/site/icons/research.png' %}" alt="Archives" border="0">
+ </span>
+ <span>
+ <a href="{% url 'blog:donate' %}">
+ Donate
+ </a>
+ </span>
+ </li>
+ <li>
+ <span>
<img src="{% static 'images/site/icons/setup.gif' %}" alt="Source Code" border="0">
</span>
<span>
diff --git a/templates/blog/post.html b/templates/blog/post.html
index ee1fe7c0..ca3e7644 100644
--- a/templates/blog/post.html
+++ b/templates/blog/post.html
@@ -15,6 +15,24 @@
<div id="article-body">{{ post.body | safe }}</div>
</div>
+<div id="donate" style="clear: both;" class="mtsbitem">
+ <h2 style="text-transform: none; border: none; margin: 0; padding: 0;">Liked this article?</h2>
+ <form action="{% url 'blog:donate' %}">
+ <input type="hidden" name="referrer" value="{{ post.slug }}" id="referrer" style="display: none;">
+ <p>
+ <span style="width:60px; display: inline-block;">Donate: </span>
+ <span style="width:90px; display: inline-block;">
+ <input type="number" name="amount" id="amount" value="5" min="3" style="width: 60px; text-align: center;" oninput="parseAmount()">
+ </span>
+ <span style="width:40px; display: inline-block;">USD</span>
+ <span style="width:100px; display: inline-block;">
+ <input type="submit" id="donate_btn" value="Donate $5" class="button button-special">
+ </span>
+ </p>
+ </form>
+</div>
+
+
<div id="comments" style="clear: both;" class="mtsbitem">
<h2>Comments</h2>
{% for comment in comments %}
@@ -127,6 +145,21 @@
}
}
+ function parseAmount(amount) {
+ var amount_input = document.getElementById('amount');
+ var donate_btn = document.getElementById('donate_btn');
+ var amount = amount_input.value;
+ amount = parseInt(amount);
+ if (isNaN(amount)) {
+ amount = 3;
+ }
+ amount = Math.max(amount, 3);
+ amount = Math.min(amount, 1000);
+ amount_input.value = amount;
+ // update donate button value
+ donate_btn.value = 'Donate $' + amount;
+ }
+
// We are aiming to keep the JS to ES3 for compatibility with older browsers.
// Get all textareas and bind the shortkeys.
var textareas = document.getElementsByTagName('textarea');