syntaxwebsite/app/routes/kofihandler.py

125 lines
4.2 KiB
Python

from flask import Blueprint, render_template, request, redirect, url_for, jsonify, make_response, abort
from config import Config
import json
import logging
from app.models.giftcard_key import GiftcardKey
from app.enums.GiftcardType import GiftcardType
from app.models.kofi_transaction import KofiTransaction
from app.extensions import db, csrf
import requests
import datetime
import random
import string
from requests.auth import HTTPBasicAuth
from config import Config
config = Config()
KofiHandlerRoute = Blueprint("kofihandler", __name__, template_folder="pages")
def GenerateCode():
Code = ""
for i in range(0, 5):
Chunk = ''.join(random.choices(string.ascii_uppercase + string.digits, k=5))
Code += Chunk
if i != 4:
Code += "-"
return Code
@KofiHandlerRoute.before_request
def before_request():
if config.KOFI_ENABLED is False:
return abort(404)
@KofiHandlerRoute.route("/internal/kofi_handler", methods=["POST"])
@csrf.exempt
def kofi_handler():
try:
PurchaseData = json.loads(
request.form.get(key="data", default=None, type=str)
)
if PurchaseData is None:
return abort(400)
except:
return abort(400)
if PurchaseData["verification_token"] != Config.KOFI_VERIFICATION_TOKEN:
return abort(401)
if "email" not in PurchaseData:
logging.error("KofiHandler: Email not in PurchaseData")
return abort(400)
UserEmail : str = PurchaseData["email"]
logging.info(f"KofiHandler: Received donation from {UserEmail}, Transaction ID: {PurchaseData['kofi_transaction_id']}")
TransactionObj : KofiTransaction = KofiTransaction.query.filter_by(kofi_transaction_id=PurchaseData["kofi_transaction_id"]).first()
if TransactionObj is not None:
logging.error(f"KofiHandler: Transaction ID {PurchaseData['kofi_transaction_id']} already exists")
return abort(400)
NewGiftcardCode : str = GenerateCode()
NewGiftcardObj : GiftcardKey = GiftcardKey(
key = NewGiftcardCode,
type = GiftcardType.Outrageous_BuildersClub,
value = 1
)
db.session.add(NewGiftcardObj)
db.session.commit()
NewTransactionObj : KofiTransaction = KofiTransaction(
kofi_transaction_id = PurchaseData["kofi_transaction_id"],
timestamp = datetime.datetime.strptime(PurchaseData["timestamp"], "%Y-%m-%dT%H:%M:%SZ"),
donation_type = PurchaseData["type"],
amount = float(PurchaseData["amount"]),
currency = PurchaseData["currency"],
is_subscription_payment = PurchaseData["is_subscription_payment"],
message = PurchaseData["message"],
from_name = PurchaseData["from_name"],
from_email = PurchaseData["email"],
assigned_key = NewGiftcardObj.key
)
db.session.add(NewTransactionObj)
db.session.commit()
EmailData = {
"Messages": [
{
"From": {
"Email": Config.MAILJET_NOREPLY_SENDER,
"Name": "Syntax Donation Processor"
},
"To": [
{
"Email": UserEmail,
"Name": PurchaseData["from_name"]
}
],
"TemplateID": Config.MAILJET_DONATION_TEMPLATE_ID,
"TemplateLanguage": True,
"Subject": "Thank you for your donation!",
"Variables": {
"redeem_key": NewGiftcardObj.key,
}
}
]
}
EmailResponse = requests.post(
url="https://api.mailjet.com/v3.1/send",
data=json.dumps(EmailData),
headers={
"Content-Type": "application/json"
},
auth = HTTPBasicAuth(
Config.MAILJET_APIKEY,
Config.MAILJET_SECRETKEY
)
)
if EmailResponse.status_code != 200:
logging.error(f"KofiHandler: Failed to send email to {UserEmail}")
logging.error(EmailResponse.json())
return "OK", 200 # We don't want to return an error to Ko-fi since we already processed the donation, so we just return OK
logging.info(f"KofiHandler: Successfully sent email to {UserEmail} and processed donation")
return "OK", 200