Flesh out donation page

This commit is contained in:
Drew DeVault 2015-09-05 17:27:41 -04:00
parent eaa42767aa
commit 7a144f71f0
6 changed files with 188 additions and 9 deletions

View File

@ -6,6 +6,7 @@ from fosspay.common import *
from fosspay.config import _cfg, load_config
import locale
import bcrypt
encoding = locale.getdefaultlocale()[1]
html = Blueprint('html', __name__, template_folder='../../templates')
@ -15,7 +16,8 @@ def index():
if User.query.count() == 0:
load_config()
return render_template("setup.html")
return render_template("index.html")
projects = sorted(Project.query.all(), key=lambda p: p.name)
return render_template("index.html", projects=projects)
@html.route("/setup", methods=["POST"])
def setup():
@ -37,12 +39,15 @@ def setup():
def admin():
first = request.args.get("first-run") is not None
projects = Project.query.all()
unspecified = Donation.query.filter(Donation.project == None).all()
return render_template("admin.html",
first=first,
projects=projects,
one_times=lambda p: sum([d.amount for d in p.donations if d.type == DonationType.one_time]),
recurring=lambda p: sum([d.amount for d in p.donations if d.type == DonationType.recurring])
)
first=first,
projects=projects,
one_times=lambda p: sum([d.amount for d in p.donations if d.type == DonationType.one_time]),
recurring=lambda p: sum([d.amount for d in p.donations if d.type == DonationType.recurring]),
unspecified_one_times=sum([d.amount for d in unspecified if d.type == DonationType.one_time]),
unspecified_recurring=sum([d.amount for d in unspecified if d.type == DonationType.recurring])
)
@html.route("/create-project", methods=["POST"])
@adminrequired
@ -53,6 +58,22 @@ def create_project():
db.commit()
return redirect("/admin")
@html.route("/login", methods=["GET", "POST"])
def login():
if request.method == "GET":
return render_template("login.html")
email = request.form.get("email")
password = request.form.get("password")
if not email or not password:
return render_template("login.html", errors=True)
user = User.query.filter(User.email == email).first()
if not user:
return render_template("login.html", errors=True)
if not bcrypt.hashpw(password.encode('UTF-8'), user.password.encode('UTF-8')) == user.password.encode('UTF-8'):
return render_template("login.html", errors=True)
login_user(user)
return redirect("/")
@html.route("/logout")
@loginrequired
def logout():

View File

@ -1,5 +1,8 @@
{% extends "layout.html" %}
{% block body %}
{% block title %}
<title>Donation Admin</title>
{% endblock %}
{% block container %}
<a href="/logout" class="pull-right">Log out</a>
<h1>Fosspay Admin</h1>
{% if first %}
@ -50,11 +53,19 @@
<td><a href="#" class="btn btn-primary btn-sm">Get Markdown</a></td>
</tr>
{% endfor %}
<tr>
<td></td>
<td>(not specified)</td>
<td>${{ unspecified_one_times }}</td>
<td>${{ unspecified_recurring }}</td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<div class="col-md-6 well">
<h4>Add Project</h4>
<p>Donors will not be given a choice of project unless you have at least 2.</p>
<form method="POST" action="/create-project">
<div class="form-group">
<input class="form-control" type="text" placeholder="Project name" name="name" />

View File

@ -0,0 +1,10 @@
<p>
Donations accumulate until they reach enough to support a week of full
time work. Once they get to this amount, a week will be scheduled. The
amount of time each project receives is planned based on the amount of
donations received that specify that project in the drop-down.
</p>
<p>
If one project receives a million dollars and another project receives
one dollar, at least an hour will be spent on the second project.
</p>

112
templates/index.html Normal file
View File

@ -0,0 +1,112 @@
{% extends "layout.html" %}
{% 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>
</div>
<noscript>
<div class="container">
<div class="alert alert-danger">
<p>This page requires Javascript. It's necessary to send your credit card number to
<a href="https://stripe.com/">Stripe</a> directly, so you don't need to trust me with it.</p>
</div>
</div>
</noscript>
<div class="container text-center">
<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" role="group">
<button type="button" class="btn btn-default">$5</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default">$10</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default">$20</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default">$50</button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-default">Custom</button>
</div>
</div>
</div>
</div>
<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>
</div>
</div>
</div>
</div>
{% if len(projects) > 1 %}
<h3>What project?</h3>
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="form-group">
<select>
<option value="none">None in particular</option>
{% for project in projects %}
<option value="{{ project.id }}">{{ project.name }}</option>
{% endfor %}
</select>
</div>
</div>
</div>
{% endif %}
<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?" />
</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>
</div>
</div>
</div>
<hr />
<div class="container text-center">
<p>
<small class="text-muted">
Been here before? <a href="/login">Log in</a> to view your donation
history, edit recurring donations, and so on.
</small>
</p>
<p>
<small class="text-muted">
Powered by <a href="https://github.com/SirCmpwn/fosspay">fosspay</a>.
</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">&times;</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 %}

View File

@ -5,10 +5,15 @@
<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>
</head>
<body>
{% block body %}
<div class="container">
{% block body %}{% endblock %}
{% block container %}
{% endblock %}
</div>
{% endblock %}
</body>
</html>

20
templates/login.html Normal file
View File

@ -0,0 +1,20 @@
{% extends "layout.html" %}
{% block container %}
<h1>Log In</h1>
{% if errors %}
<div class="alert alert-danger">
<p>
Username or password incorrect.
</p>
</div>
{% endif %}
<form action="/login" method="POST">
<div class="form-group">
<input class="form-control" type="text" name="email" placeholder="you@email.com" />
</div>
<div class="form-group">
<input class="form-control" type="password" name="password" placeholder="Password" />
</div>
<input type="submit" value="Log in" class="btn btn-primary" />
</form>
{% endblock %}