Flesh out donation page
This commit is contained in:
parent
7a144f71f0
commit
db7cd6dd17
8
Makefile
8
Makefile
|
@ -1,7 +1,6 @@
|
|||
# Builds static assets
|
||||
# Depends on:
|
||||
# - scss
|
||||
# - coffeescript
|
||||
# - inotify-tools
|
||||
# Run `make` to compile static assets
|
||||
# Run `make watch` to recompile whenever a change is made
|
||||
|
@ -10,8 +9,7 @@
|
|||
|
||||
STYLES:=$(patsubst styles/%.scss,static/%.css,$(wildcard styles/*.scss))
|
||||
STYLES+=$(patsubst styles/%.css,static/%.css,$(wildcard styles/*.css))
|
||||
SCRIPTS:=$(patsubst scripts/%.coffee,static/%.js,$(wildcard scripts/*.coffee))
|
||||
SCRIPTS+=$(patsubst scripts/%.js,static/%.js,$(wildcard scripts/*.js))
|
||||
SCRIPTS:=$(patsubst scripts/%.js,static/%.js,$(wildcard scripts/*.js))
|
||||
_STATIC:=$(patsubst _static/%,static/%,$(wildcard _static/*))
|
||||
|
||||
static/%: _static/%
|
||||
|
@ -30,10 +28,6 @@ static/%.js: scripts/%.js
|
|||
@mkdir -p static/
|
||||
cp $< $@
|
||||
|
||||
static/%.js: scripts/%.coffee
|
||||
@mkdir -p static/
|
||||
coffee -m -o static/ -c $<
|
||||
|
||||
static: $(STYLES) $(SCRIPTS) $(_STATIC)
|
||||
|
||||
all: static
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 593 B |
|
@ -19,6 +19,7 @@ smtp-from=donate@you.com
|
|||
# Your information
|
||||
your_name=Joe Bloe
|
||||
your_email=joe@bloe.com
|
||||
# ^ you should have a gravatar that works with this email
|
||||
|
||||
# SQL connection string
|
||||
connection-string=postgresql://postgres@localhost/fosspay
|
||||
|
|
|
@ -12,6 +12,8 @@ from fosspay.objects import User
|
|||
from fosspay.common import *
|
||||
from fosspay.network import *
|
||||
|
||||
import fosspay.stripe
|
||||
|
||||
from fosspay.blueprints.html import html
|
||||
|
||||
app = Flask(__name__)
|
||||
|
|
|
@ -7,6 +7,7 @@ from fosspay.config import _cfg, load_config
|
|||
|
||||
import locale
|
||||
import bcrypt
|
||||
import hashlib
|
||||
|
||||
encoding = locale.getdefaultlocale()[1]
|
||||
html = Blueprint('html', __name__, template_folder='../../templates')
|
||||
|
@ -17,7 +18,8 @@ def index():
|
|||
load_config()
|
||||
return render_template("setup.html")
|
||||
projects = sorted(Project.query.all(), key=lambda p: p.name)
|
||||
return render_template("index.html", projects=projects)
|
||||
avatar = "//www.gravatar.com/avatar/" + hashlib.md5(_cfg("your-email").encode("utf-8")).hexdigest()
|
||||
return render_template("index.html", projects=projects, avatar=avatar)
|
||||
|
||||
@html.route("/setup", methods=["POST"])
|
||||
def setup():
|
||||
|
|
|
@ -58,12 +58,14 @@ class Donation(Base):
|
|||
type = Column(ChoiceType(DonationType, impl=String()))
|
||||
amount = Column(Integer, nullable=False)
|
||||
created = Column(DateTime, nullable=False)
|
||||
emailed_about = Column(Boolean, nullable=False)
|
||||
|
||||
def __init__(self, user, type, amount):
|
||||
self.user = user
|
||||
self.type = type
|
||||
self.amount = amount
|
||||
self.created = datetime.now()
|
||||
self.emailed_about = False
|
||||
|
||||
def __repr__(self):
|
||||
return "<Donation {} from {}: ${} ({})>".format(
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
from fosspay.config import _cfg
|
||||
|
||||
import stripe
|
||||
|
||||
if _cfg("stripe-secret") != "":
|
||||
stripe.api_key = _cfg("stripe-secret")
|
|
@ -0,0 +1,105 @@
|
|||
(function() {
|
||||
var donation = {
|
||||
type: "monthly",
|
||||
amount: 1000, // cents
|
||||
project: null,
|
||||
comment: null
|
||||
};
|
||||
|
||||
function selectAmount(e) {
|
||||
e.preventDefault();
|
||||
document.querySelector(".amounts .active").classList.remove("active");
|
||||
e.target.classList.add("active");
|
||||
var custom = document.querySelector("#custom-amount");
|
||||
var amount = e.target.dataset.amount;
|
||||
if (amount === "custom") {
|
||||
custom.classList.remove("hidden");
|
||||
donation.amount = +document.querySelector("#custom-amount-text").value * 100;
|
||||
} else {
|
||||
custom.classList.add("hidden");
|
||||
donation.amount = +e.target.dataset.amount * 100;
|
||||
}
|
||||
}
|
||||
|
||||
function selectFrequency(e) {
|
||||
e.preventDefault();
|
||||
document.querySelector(".frequencies .active").classList.remove("active");
|
||||
e.target.classList.add("active");
|
||||
donation.type = e.target.dataset.frequency;
|
||||
}
|
||||
|
||||
var amounts = document.querySelectorAll(".amounts button");
|
||||
for (var i = 0; i < amounts.length; i++) {
|
||||
amounts[i].addEventListener("click", selectAmount);
|
||||
}
|
||||
|
||||
var frequencies = document.querySelectorAll(".frequencies button");
|
||||
for (var i = 0; i < frequencies.length; i++) {
|
||||
frequencies[i].addEventListener("click", selectFrequency);
|
||||
}
|
||||
|
||||
document.getElementById("custom-amount-text").addEventListener("change", function(e) {
|
||||
var value = +e.target.value;
|
||||
if (isNaN(value)) {
|
||||
value = 1;
|
||||
}
|
||||
e.target.value = value;
|
||||
donation.amount = value * 100;
|
||||
});
|
||||
|
||||
var project = document.getElementById("project")
|
||||
if (project) {
|
||||
project.addEventListener("change", function(e) {
|
||||
if (e.target.value === "null") {
|
||||
donation.project = null;
|
||||
} else {
|
||||
donation.project = e.target.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("donate-button").addEventListener("click", function(e) {
|
||||
e.preventDefault();
|
||||
if (e.target.getAttribute("disabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
var handler = StripeCheckout.configure({
|
||||
name: your_name,
|
||||
key: window.stripe_key,
|
||||
image: window.avatar,
|
||||
locale: 'auto',
|
||||
description: donation.type == "monthly" ? "Monthly Donation" : "One-time Donation",
|
||||
panelLabel: "Donate {{amount}}",
|
||||
amount: donation.amount,
|
||||
bitcoin: donation.type == "once",
|
||||
token: function(token) {
|
||||
e.target.setAttribute("disabled", "");
|
||||
e.target.textContent = "Submitting...";
|
||||
|
||||
var data = new FormData();
|
||||
data.append("stripe_token", token.id);
|
||||
data.append("email", token.email);
|
||||
data.append("amount", donation.amount);
|
||||
data.append("type", donation.type);
|
||||
data.append("comment", donation.comment);
|
||||
if (donation.project !== null) {
|
||||
data.append("project", donation.project);
|
||||
}
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "donate");
|
||||
xhr.onload = function() {
|
||||
document.getElementById("donation-stuff").classList.add("hidden");
|
||||
document.getElementById("thanks").classList.remove("hidden");
|
||||
var res = JSON.parse(this.responseText);
|
||||
if (res.newAccount) {
|
||||
document.getElementById("new-donor-password").classList.remove("hidden");
|
||||
}
|
||||
};
|
||||
xhr.send(data);
|
||||
}
|
||||
});
|
||||
|
||||
handler.open();
|
||||
});
|
||||
})();
|
|
@ -1,9 +1,29 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block scripts %}
|
||||
<script>
|
||||
window.stripe_key = "{{ _cfg("stripe-publish") }}";
|
||||
window.avatar = "{{ avatar }}";
|
||||
window.your_name = "{{ _cfg("your-name") }}";
|
||||
</script>
|
||||
<script src="//checkout.stripe.com/checkout.js"></script>
|
||||
<script src="static/index.js"></script>
|
||||
{% endblock %}
|
||||
{% block body %}
|
||||
<div class="well">
|
||||
<div class="container">
|
||||
<h1>Donate to {{ _cfg("your-name") }}</h1>
|
||||
<p><a href="#" data-toggle="modal" data-target="#how-this-works-modal">How does this work?</a></p>
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<p>
|
||||
Donations accumulate until there's enough to fund one week of
|
||||
full time development. The project you specify influences which
|
||||
projects receive the most time. Each donated-to project will
|
||||
receive attention, even if there's just one donation for it.
|
||||
Monthly donations will help me keep doing this for a long time,
|
||||
but one-offs are also great.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<noscript>
|
||||
|
@ -14,25 +34,44 @@
|
|||
</div>
|
||||
</div>
|
||||
</noscript>
|
||||
<div class="container text-center">
|
||||
<div class="container text-center hidden" id="thanks">
|
||||
{% include "post-donation-message.html" %}
|
||||
<div id="new-donor-password" class="hidden">
|
||||
<p>Set a password now if you want to manage your donations later:</p>
|
||||
<input type="password" placeholder="Password" />
|
||||
<button class="btn btn-primary btn-sm">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container text-center" id="donation-stuff">
|
||||
<h3>How much?</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
<div class="btn-group btn-group-justified" role="group" aria-label="...">
|
||||
<div class="btn-group btn-group-justified amounts" role="group" aria-label="...">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default">$5</button>
|
||||
<button data-amount="5" type="button" class="btn btn-default">$5</button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default">$10</button>
|
||||
<button data-amount="10" type="button" class="btn btn-default active">$10</button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default">$20</button>
|
||||
<button data-amount="20" type="button" class="btn btn-default">$20</button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default">$50</button>
|
||||
<button data-amount="50" type="button" class="btn btn-default">$50</button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default">Custom</button>
|
||||
<button data-amount="custom" type="button" class="btn btn-default">Custom</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row hidden" id="custom-amount" style="margin-top: 20px;">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">$</span>
|
||||
<input id="custom-amount-text" type="text" value="1"
|
||||
class="form-control" placeholder="Amount" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -40,12 +79,17 @@
|
|||
<h3>How often?</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="btn-group btn-group-justified" role="group" aria-label="...">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default">Once</button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default">Monthly</button>
|
||||
<p class="text-muted"><small>Bitcoin is only supported for one-time donations.</small></p>
|
||||
<div class="form-group">
|
||||
<div class="btn-group btn-group-justified frequencies" role="group" aria-label="...">
|
||||
<div class="btn-group" role="group">
|
||||
<button data-frequency="once" type="button"
|
||||
class="btn btn-default">Once</button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button data-frequency="monthly" type="button"
|
||||
class="btn btn-default active">Monthly</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -55,8 +99,8 @@
|
|||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="form-group">
|
||||
<select>
|
||||
<option value="none">None in particular</option>
|
||||
<select id="project" class="form-control">
|
||||
<option value="null">None in particular</option>
|
||||
{% for project in projects %}
|
||||
<option value="{{ project.id }}">{{ project.name }}</option>
|
||||
{% endfor %}
|
||||
|
@ -68,13 +112,13 @@
|
|||
<div class="row">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" placeholder="Any comments?" />
|
||||
<input type="text" id="comments" class="form-control" placeholder="Any comments?" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-top: 50px">
|
||||
<div class="col-md-4 col-md-offset-4">
|
||||
<button class="btn btn-block btn-success">Donate</button>
|
||||
<button class="btn btn-block btn-success" id="donate-button">Donate</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -92,21 +136,4 @@
|
|||
</small>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="how-this-works-modal" tabindex="-1" role="dialog" aria-labelledby="how-label">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title" id="how-label">How does this work?</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{% include "how-this-works.html" %}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Dismiss</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="static/icon.png" type="image/png" />
|
||||
{% block title %}
|
||||
<title>Donate to {{_cfg("your-name")}}</title>
|
||||
{% endblock %}
|
||||
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
|
||||
{% block styles %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}
|
||||
|
@ -15,5 +16,8 @@
|
|||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
||||
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block container %}
|
||||
<h1>404 Not Found</h1>
|
||||
<p><a href="/">Trying to donate?</a></p>
|
||||
{% endblock %}
|
|
@ -0,0 +1,2 @@
|
|||
<h3>Thanks!</h3>
|
||||
<p>You'll get an email when your money is going to be put to work.</p>
|
|
@ -1,5 +1,5 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
{% block container %}
|
||||
<h1>FossPay Setup</h1>
|
||||
<p>Congrats! You have FossPay up and running.</p>
|
||||
|
||||
|
|
Loading…
Reference in New Issue