def send_new_donation(user, donation): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) with open("emails/new_donation") as f: message = MIMEText(html.parser.HTMLParser().unescape(\ pystache.render(f.read(), { "user": user, "root": _cfg("protocol") + "://" + _cfg("domain"), "your_name": _cfg("your-name"), "amount": currency.amount("{:.2f}".format( donation.amount / 100)), "frequency": (" per month" if donation.type == DonationType.monthly else ""), "comment": donation.comment or "", }))) message['Subject'] = "New donation on fosspay!" message['From'] = _cfg("smtp-from") message['To'] = f"{_cfg('your-name')} <{_cfg('your-email')}>" message['Date'] = format_datetime(localtime()) smtp.sendmail(_cfg("smtp-from"), [_cfg('your-email')], message.as_string()) smtp.quit()
def send_thank_you(user, amount, monthly): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) with open("emails/thank-you") as f: message = MIMEText( html.parser.HTMLParser().unescape( pystache.render( f.read(), { "user": user, "root": _cfg("protocol") + "://" + _cfg("domain"), "your_name": _cfg("your-name"), "amount": "{:.2f}".format(amount / 100), "monthly": monthly, "your_email": _cfg("your-email"), }, ) ) ) message["Subject"] = "Thank you for your donation!" message["From"] = _cfg("smtp-from") message["To"] = user.email smtp.sendmail(_cfg("smtp-from"), [user.email], message.as_string()) smtp.quit()
def send_password_reset(user): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) with open("emails/reset-password") as f: message = MIMEText( html.parser.HTMLParser().unescape( pystache.render( f.read(), { "user": user, "root": _cfg("protocol") + "://" + _cfg("domain"), "your_name": _cfg("your-name"), "your_email": _cfg("your-email"), }, ) ) ) message["Subject"] = "Reset your donor password" message["From"] = _cfg("smtp-from") message["To"] = user.email smtp.sendmail(_cfg("smtp-from"), [user.email], message.as_string()) smtp.quit()
def index(): if User.query.count() == 0: load_config() return render_template("setup.html") projects = sorted(Project.query.all(), key=lambda p: p.name) avatar = "//www.gravatar.com/avatar/" + hashlib.md5( _cfg("your-email").encode("utf-8")).hexdigest() selected_project = request.args.get("project") if selected_project: try: selected_project = int(selected_project) except: selected_project = None active_recurring = (Donation.query.filter( Donation.type == DonationType.monthly).filter( Donation.active == True).filter(Donation.hidden == False)) recurring_count = active_recurring.count() recurring_sum = sum([d.amount for d in active_recurring]) access_token = _cfg("patreon-access-token") campaign = _cfg("patreon-campaign") if access_token and campaign: try: import patreon client = patreon.API(access_token) campaign = client.fetch_campaign() attrs = campaign.json_data["data"][0]["attributes"] patreon_count = attrs["patron_count"] patreon_sum = attrs["pledge_sum"] except: patreon_count = 0 patreon_sum = 0 else: patreon_count = 0 patreon_sum = 0 liberapay = _cfg("liberapay-campaign") if liberapay: lp = (requests.get( "https://liberapay.com/{}/public.json".format(liberapay))).json() lp_count = lp['npatrons'] lp_sum = int(float(lp['receiving']['amount']) * 100) # Convert from weekly to monthly lp_sum = lp_sum * 52 // 12 else: lp_count = 0 lp_sum = 0 return render_template("index.html", projects=projects, avatar=avatar, selected_project=selected_project, recurring_count=recurring_count, recurring_sum=recurring_sum, patreon_count=patreon_count, patreon_sum=patreon_sum, lp_count=lp_count, lp_sum=lp_sum, currency=currency)
def inject(): return { 'root': _cfg("protocol") + "://" + _cfg("domain"), 'domain': _cfg("domain"), 'protocol': _cfg("protocol"), 'len': len, 'any': any, 'request': request, 'locale': locale, 'url_for': url_for, 'file_link': file_link, 'user': current_user, '_cfg': _cfg, '_cfgi': _cfgi, 'debug': app.debug, 'str': str }
def inject(): return { 'root': _cfg("protocol") + "://" + _cfg("domain"), 'domain': _cfg("domain"), 'protocol': _cfg("protocol"), 'len': len, 'any': any, 'request': request, 'locale': locale, 'url_for': url_for, 'file_link': file_link, 'user': current_user, '_cfg': _cfg, '_cfgi': _cfgi, 'debug': app.debug, 'str': str, 'int': int }
def send_password_reset(user): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) message = MIMEText( render_template("emails/reset-password", user=user, root=_cfg("protocol") + "://" + _cfg("domain"), your_name=_cfg("your-name"), your_email=_cfg("your-email"))) message['Subject'] = "Reset your donor password" message['From'] = _cfg("smtp-from") message['To'] = user.email message['Date'] = format_datetime(localtime()) smtp.sendmail(_cfg("smtp-from"), [user.email], message.as_string()) smtp.quit()
def send_password_reset(user): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) with open("emails/reset-password") as f: message = MIMEText(html.parser.HTMLParser().unescape(\ pystache.render(f.read(), { "user": user, "root": _cfg("protocol") + "://" + _cfg("domain"), "your_name": _cfg("your-name"), "your_email": _cfg("your-email") }))) message['Subject'] = "Reset your donor password" message['From'] = _cfg("smtp-from") message['To'] = user.email message['Date'] = format_datetime(localtime()) smtp.sendmail(_cfg("smtp-from"), [user.email], message.as_string()) smtp.quit()
def send_cancellation_notice(user, donation): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) message = MIMEText( render_template( "emails/cancelled", user=user, root=_cfg("protocol") + "://" + _cfg("domain"), your_name=_cfg("your-name"), amount=currency.amount("{:.2f}".format(donation.amount / 100)), )) message['Subject'] = "A monthly donation on ShleePay has been cancelled" message['From'] = _cfg("smtp-from") message['To'] = f"{_cfg('your-name')} <{_cfg('your-email')}>" message['Date'] = format_datetime(localtime()) smtp.sendmail(_cfg("smtp-from"), [_cfg('your-email')], message.as_string()) smtp.quit()
def send_thank_you(user, amount, monthly): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) message = MIMEText( render_template("emails/thank-you", user=user, root=_cfg("protocol") + "://" + _cfg("domain"), your_name=_cfg("your-name"), amount=currency.amount("{:.2f}".format(amount / 100)), monthly=monthly, your_email=_cfg("your-email"))) message['Subject'] = "Thank you for your donation!" message['From'] = _cfg("smtp-from") message['To'] = user.email message['Date'] = format_datetime(localtime()) smtp.sendmail(_cfg("smtp-from"), [user.email], message.as_string()) smtp.quit()
def send_cancellation_notice(user, donation): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) with open("emails/cancelled") as f: message = MIMEText(html.parser.HTMLParser().unescape(\ pystache.render(f.read(), { "user": user, "root": _cfg("protocol") + "://" + _cfg("domain"), "your_name": _cfg("your-name"), "amount": currency.amount("{:.2f}".format( donation.amount / 100)), }))) message['Subject'] = "A monthly donation on fosspay has been cancelled" message['From'] = _cfg("smtp-from") message['To'] = f"{_cfg('your-name')} <{_cfg('your-email')}>" message['Date'] = format_datetime(localtime()) smtp.sendmail(_cfg("smtp-from"), [_cfg('your-email')], message.as_string()) smtp.quit()
def index(): if User.query.count() == 0: load_config() return render_template("setup.html") projects = sorted(Project.query.all(), key=lambda p: p.name) avatar = "//www.gravatar.com/avatar/" + hashlib.md5(_cfg("your-email").encode("utf-8")).hexdigest() selected_project = request.args.get("project") if selected_project: try: selected_project = int(selected_project) except: selected_project = None return render_template("index.html", projects=projects, avatar=avatar, selected_project=selected_project)
def send_thank_you(user, amount, monthly): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) with open("emails/thank-you") as f: message = MIMEText(html.parser.HTMLParser().unescape(\ pystache.render(f.read(), { "user": user, "root": _cfg("protocol") + "://" + _cfg("domain"), "your_name": _cfg("your-name"), "amount": currency.amount("{:.2f}".format(amount / 100)), "monthly": monthly, "your_email": _cfg("your-email") }))) message['Subject'] = "Thank you for your donation!" message['From'] = _cfg("smtp-from") message['To'] = user.email message['Date'] = format_datetime(localtime()) smtp.sendmail(_cfg("smtp-from"), [user.email], message.as_string()) smtp.quit()
def send_new_donation(user, donation): if _cfg("smtp-host") == "": return smtp = smtplib.SMTP(_cfg("smtp-host"), _cfgi("smtp-port")) smtp.ehlo() smtp.starttls() smtp.login(_cfg("smtp-user"), _cfg("smtp-password")) message = MIMEText( render_template( "emails/new_donation", user=user, root=_cfg("protocol") + "://" + _cfg("domain"), your_name=_cfg("your-name"), amount=currency.amount("{:.2f}".format(donation.amount / 100)), frequency=(" per month" if donation.type == DonationType.monthly else ""), comment=donation.comment or "")) message['Subject'] = "New donation on ShleePay!" message['From'] = _cfg("smtp-from") message['To'] = f"{_cfg('your-name')} <{_cfg('your-email')}>" message['Date'] = format_datetime(localtime()) smtp.sendmail(_cfg("smtp-from"), [_cfg('your-email')], message.as_string()) smtp.quit()
import sys from fosspay.app import app from fosspay.objects import * from fosspay.database import db from fosspay.config import _cfg from fosspay.email import send_thank_you, send_declined from fosspay.currency import currency from datetime import datetime, timedelta import requests import stripe with app.app_context(): stripe.api_key = _cfg("stripe-secret") # Date in global standard print("Processing monthly donations @ {}".format( datetime.now().strftime('%d-%m-%Y %H:%M:%S'))) donations = Donation.query \ .filter(Donation.type == DonationType.monthly) \ .filter(Donation.active) \ .all() limit = datetime.now() - timedelta(days=30) for donation in donations: if donation.updated < limit: print("Charging {}".format(donation))
from fosspay.config import _cfg class Currency: def __init__(self, symbol, position): self.symbol = symbol self.position = position def amount(self, amount): if self.position == "right": return amount + self.symbol else: return self.symbol + amount currencies = { 'usd': Currency("$", "left"), 'eur': Currency("€", "right") # ... More currencies can be added here } currency = currencies[_cfg("currency")]
#!/usr/bin/env python3 from fosspay.objects import * from fosspay.database import db from fosspay.config import _cfg from fosspay.email import send_thank_you, send_declined from datetime import datetime, timedelta import requests import stripe import subprocess stripe.api_key = _cfg("stripe-secret") print("Processing monthly donations") donations = Donation.query \ .filter(Donation.type == DonationType.monthly) \ .filter(Donation.active) \ .all() limit = datetime.now() - timedelta(days=30) for donation in donations: if donation.updated < limit: print("Charging {}".format(donation)) user = donation.user customer = stripe.Customer.retrieve(user.stripe_customer) try: charge = stripe.Charge.create(amount=donation.amount, currency="usd",
#!/usr/bin/env python3 from fosspay.objects import * from fosspay.database import db from fosspay.config import _cfg from fosspay.email import send_thank_you, send_declined from datetime import datetime, timedelta import stripe stripe.api_key = _cfg("stripe-secret") print("Processing monthly donations") donations = Donation.query \ .filter(Donation.type == DonationType.monthly) \ .filter(Donation.active) \ .all() limit = datetime.now() - timedelta(days=30) for donation in donations: if donation.updated < limit: print("Charging {}".format(donation)) user = donation.user customer = stripe.Customer.retrieve(user.stripe_customer) try: charge = stripe.Charge.create( amount=donation.amount, currency="usd", customer=user.stripe_customer,
def file_link(path): return _cfg("protocol") + "://" + _cfg("domain") + "/" + path
def logout(): logout_user() return redirect(_cfg("protocol") + "://" + _cfg("domain"))
def disown_link(path): return _cfg("protocol") + "://" + _cfg("domain") + "/disown?filename=" + path
#!/usr/bin/env python3 from fosspay.objects import * from fosspay.database import db from fosspay.config import _cfg from fosspay.email import send_thank_you, send_declined from datetime import datetime, timedelta import stripe stripe.api_key = _cfg("stripe-secret") print("Processing monthly donations") donations = Donation.query \ .filter(Donation.type == DonationType.monthly) \ .filter(Donation.active) \ .all() limit = datetime.now() - timedelta(days=30) for donation in donations: if donation.updated < limit: print("Charging {}".format(donation)) user = donation.user customer = stripe.Customer.retrieve(user.stripe_customer) try: charge = stripe.Charge.create(amount=donation.amount, currency="usd", customer=user.stripe_customer, description="Donation to " +
import sys import os import locale import stripe from fosspay.config import _cfg, _cfgi from fosspay.database import db, init_db from fosspay.objects import User from fosspay.common import * from fosspay.network import * from fosspay.blueprints.html import html app = Flask(__name__) app.secret_key = _cfg("secret-key") app.jinja_env.cache = None init_db() login_manager = LoginManager() login_manager.init_app(app) app.jinja_loader = ChoiceLoader([ FileSystemLoader("overrides"), FileSystemLoader("templates"), ]) stripe.api_key = _cfg("stripe-secret") @login_manager.user_loader def load_user(email): return User.query.filter(User.email == email).first()
def index(): if User.query.count() == 0: load_config() return render_template("setup.html") projects = sorted(Project.query.all(), key=lambda p: p.name) if os.path.exists('static/logo.png'): avatar = os.path.join('static/logo.png') else: avatar = "//www.gravatar.com/avatar/" + hashlib.md5(_cfg("your-email").encode("utf-8")).hexdigest() selected_project = request.args.get("project") if selected_project: try: selected_project = int(selected_project) except: selected_project = None active_recurring = (Donation.query .filter(Donation.type == DonationType.monthly) .filter(Donation.active == True) .filter(Donation.hidden == False)) recurring_count = active_recurring.count() recurring_sum = sum([d.amount for d in active_recurring]) access_token = _cfg("patreon-access-token") campaign = _cfg("patreon-campaign") if access_token and campaign: try: import patreon client = patreon.API(access_token) campaign = client.fetch_campaign() attrs = campaign.json_data["data"][0]["attributes"] patreon_count = attrs["patron_count"] patreon_sum = attrs["pledge_sum"] except: import traceback traceback.print_exc() patreon_count = 0 patreon_sum = 0 else: patreon_count = 0 patreon_sum = 0 liberapay = _cfg("liberapay-campaign") if liberapay: lp = (requests .get("https://liberapay.com/{}/public.json".format(liberapay)) ).json() lp_count = lp['npatrons'] lp_sum = int(float(lp['receiving']['amount']) * 100) # Convert from weekly to monthly lp_sum = lp_sum * 52 // 12 else: lp_count = 0 lp_sum = 0 opencollective = _cfg("opencollective-campaign") if opencollective: oc = requests.get("https://opencollective.com/{}.json".format(opencollective)).json() oc_count = oc['backersCount'] oc_sum = int(oc['yearlyIncome']) # Convert from yearly to monthly oc_sum = oc_sum // 12 else: oc_count = 0 oc_sum = 0 github_token = _cfg("github-token") if github_token: query = """ { viewer { login sponsorsListing { tiers(first:100) { nodes { monthlyPriceInCents adminInfo { sponsorships(includePrivate:true) { totalCount } } } } } } } """ r = requests.post("https://api.github.com/graphql", json={ "query": query }, headers={ "Authorization": "bearer {}".format(github_token) }) result = r.json() nodes = result["data"]["viewer"]["sponsorsListing"]["tiers"]["nodes"] cnt = lambda n: n["adminInfo"]["sponsorships"]["totalCount"] gh_count = sum(cnt(n) for n in nodes) gh_sum = sum(n["monthlyPriceInCents"] * cnt(n) for n in nodes) gh_user = result["data"]["viewer"]["login"] else: gh_count = 0 gh_sum = 0 gh_user = 0 return render_template("index.html", projects=projects, avatar=avatar, selected_project=selected_project, recurring_count=recurring_count, recurring_sum=recurring_sum, patreon_count=patreon_count, patreon_sum=patreon_sum, lp_count=lp_count, lp_sum=lp_sum, gh_count=gh_count, gh_sum=gh_sum, gh_user=gh_user, oc_count=oc_count, oc_sum=oc_sum, currency=currency)
def donate(): email = request.form.get("email") stripe_token = request.form.get("stripe_token") amount = request.form.get("amount") type = request.form.get("type") comment = request.form.get("comment") project_id = request.form.get("project") # validate and rejigger the form inputs if not email or not stripe_token or not amount or not type: return {"success": False, "reason": "Invalid request"}, 400 try: if project_id is None or project_id == "null": project = None else: project_id = int(project_id) project = Project.query.filter(Project.id == project_id).first() if type == "once": type = DonationType.one_time else: type = DonationType.monthly amount = int(amount) except: return {"success": False, "reason": "Invalid request"}, 400 new_account = False user = User.query.filter(User.email == email).first() if not user: new_account = True user = User(email, binascii.b2a_hex(os.urandom(20)).decode("utf-8")) user.password_reset = binascii.b2a_hex(os.urandom(20)).decode("utf-8") user.password_reset_expires = datetime.now() + timedelta(days=1) customer = stripe.Customer.create(email=user.email, card=stripe_token) user.stripe_customer = customer.id db.add(user) else: customer = stripe.Customer.retrieve(user.stripe_customer) new_source = customer.sources.create(source=stripe_token) customer.default_source = new_source.id customer.save() donation = Donation(user, type, amount, project, comment) db.add(donation) try: charge = stripe.Charge.create(amount=amount, currency=_cfg("currency"), customer=user.stripe_customer, description="Donation to " + _cfg("your-name")) except stripe.error.CardError as e: db.rollback() db.close() return {"success": False, "reason": "Your card was declined."} db.commit() send_thank_you(user, amount, type == DonationType.monthly) if new_account: return { "success": True, "new_account": new_account, "password_reset": user.password_reset } else: return {"success": True, "new_account": new_account}
from fosspay.config import _cfg import stripe if _cfg("stripe-secret") != "": stripe.api_key = _cfg("stripe-secret")
from fosspay.app import app from fosspay.config import _cfg, _cfgi import os app.static_folder = os.path.join(os.getcwd(), "static") import os if __name__ == '__main__': app.run(host=_cfg("debug-host"), port=_cfgi('debug-port'), debug=True)
def disown_link(path): return _cfg("protocol") + "://" + _cfg( "domain") + "/disown?filename=" + path
def donate(): email = request.form.get("email") stripe_token = request.form.get("stripe_token") amount = request.form.get("amount") type = request.form.get("type") comment = request.form.get("comment") project_id = request.form.get("project") # validate and rejigger the form inputs if not email or not stripe_token or not amount or not type: return {"success": False, "reason": "Invalid request"}, 400 try: if project_id is None or project_id == "null": project = None else: project_id = int(project_id) project = Project.query.filter(Project.id == project_id).first() if type == "once": type = DonationType.one_time else: type = DonationType.monthly amount = int(amount) except: return {"success": False, "reason": "Invalid request"}, 400 new_account = False user = User.query.filter(User.email == email).first() if not user: new_account = True user = User(email, binascii.b2a_hex(os.urandom(20)).decode("utf-8")) user.password_reset = binascii.b2a_hex(os.urandom(20)).decode("utf-8") user.password_reset_expires = datetime.now() + timedelta(days=1) customer = stripe.Customer.create(email=user.email, card=stripe_token) user.stripe_customer = customer.id db.add(user) else: customer = stripe.Customer.retrieve(user.stripe_customer) new_source = customer.sources.create(source=stripe_token) customer.default_source = new_source.id customer.save() donation = Donation(user, type, amount, project, comment) db.add(donation) try: charge = stripe.Charge.create( amount=amount, currency="usd", customer=user.stripe_customer, description="Donation to " + _cfg("your-name") ) except stripe.error.CardError as e: db.rollback() db.close() return {"success": False, "reason": "Your card was declined."} db.commit() send_thank_you(user, amount, type == DonationType.monthly) if new_account: return {"success": True, "new_account": new_account, "password_reset": user.password_reset} else: return {"success": True, "new_account": new_account}