forked from mirror/fosspay
commit
1059a4d62d
@ -0,0 +1,14 @@ |
||||
*.pyc |
||||
bin/ |
||||
config.ini |
||||
alembic.ini |
||||
include/ |
||||
local/ |
||||
lib/ |
||||
static/ |
||||
*.swp |
||||
*.rdb |
||||
storage/ |
||||
pip-selfcheck.json |
||||
.sass-cache/ |
||||
overrides/ |
@ -0,0 +1,19 @@ |
||||
Copyright (c) 2015 Drew DeVault |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of |
||||
this software and associated documentation files (the "Software"), to deal in |
||||
the Software without restriction, including without limitation the rights to |
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
||||
of the Software, and to permit persons to whom the Software is furnished to do |
||||
so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,51 @@ |
||||
# 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
|
||||
|
||||
.PHONY: all static watch clean |
||||
|
||||
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))
|
||||
_STATIC:=$(patsubst _static/%,static/%,$(wildcard _static/*))
|
||||
|
||||
static/%: _static/% |
||||
@mkdir -p static/
|
||||
cp $< $@
|
||||
|
||||
static/%.css: styles/%.css |
||||
@mkdir -p static/
|
||||
cp $< $@
|
||||
|
||||
static/%.css: styles/%.scss |
||||
@mkdir -p static/
|
||||
scss -I styles/ $< $@
|
||||
|
||||
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 |
||||
echo $(STYLES)
|
||||
echo $(SCRIPTS)
|
||||
|
||||
clean: |
||||
rm -rf static
|
||||
|
||||
watch: |
||||
while inotifywait \
|
||||
-e close_write scripts/ \
|
||||
-e close_write styles/ \
|
||||
-e close_write _static/; \
|
||||
do make; done
|
@ -0,0 +1,107 @@ |
||||
# fosspay |
||||
|
||||
Helps you get paid for your open source work. |
||||
|
||||
[![](https://img.shields.io/badge/Donations-fosspay-brightgreen.svg)](https://drewdevault.com/donate) |
||||
|
||||
## Rationale |
||||
|
||||
I write a ton of open source software, but almost none of it is on the scale |
||||
that I can expect reliable income from donations, or the sorts of projects that |
||||
a business would be likely to fund. It's very unlikely that I'd receive enough |
||||
donations from random folks to support full time open source work, but full time |
||||
is the best way to make serious progress on your projects. |
||||
|
||||
So - here's how this works: supporters give you one-time or recurring donations, |
||||
and after a while you get enough to take a week off from work to spend on open |
||||
source work. Since I have several projects, I also ask supporters to tell me |
||||
what project they're donating towards, and I distribute the load based on which |
||||
projects receive the most support. |
||||
|
||||
## Before you start |
||||
|
||||
Talk to your employer. The way that this is designed to work is that you |
||||
continue working full-time at your job, and collect donations. After a while, |
||||
you should have enough donations to take some period of unpaid leave - a week, a |
||||
month, or whatever works. |
||||
|
||||
* You keep your current job and job security |
||||
* You get paid to work on FOSS even with flaky or inconsistent donations |
||||
* Everyone wins |
||||
|
||||
There are a few things you need to talk about with your employer: |
||||
|
||||
1. Make sure you own the IP for the things you write during your open source |
||||
sprints. |
||||
1. Make sure that you have a job to come back to afterwards. |
||||
1. Research the tax implications of accepting these donations. |
||||
|
||||
### Stripe |
||||
|
||||
Payments are taken through Stripe, which is pretty headache-free for you to use. |
||||
You need to set up an approved Stripe account, which you can get from here: |
||||
|
||||
https://stripe.com/ |
||||
|
||||
### Mandrill |
||||
|
||||
You will need a mail server of some sort. If you don't want to go through the |
||||
trouble of setting one up, you can use Mandrill: |
||||
|
||||
http://mandrill.com/ |
||||
|
||||
You can probably also use your existing mail server, which is what I do, which |
||||
makes it easy for people to email you questions and such. |
||||
|
||||
### SSL |
||||
|
||||
You will need an SSL certificate for your website (you also need a domain name). |
||||
You can get a free SSL certificate from [StartSSL](http://www.startssl.com/), |
||||
but they've always felt pretty... bad to me. You can pay for one instead at |
||||
[RapidSSL](https://www.rapidssl.com/), which is what I use personally. You can |
||||
also get one for free from [Let's Encrypt](https://letsencrypt.org/) if that |
||||
ever happens. |
||||
|
||||
If you need a domain, you can use my referral link for |
||||
[Namecheap](http://www.namecheap.com/?aff=84838) and that'd be super nice of |
||||
you. Here's a link to Namecheap without the referral link: |
||||
[Namecheap](http://www.namecheap.com). |
||||
|
||||
## Installation |
||||
|
||||
Install these things (Arch Linux packages in parenthesis): |
||||
|
||||
* Python 3 (python) |
||||
* PostgreSQL (postgresql) |
||||
* scss (ruby-sass) |
||||
* Flask (python-flask) |
||||
* SQLAlchemy (python-sqlalchemy) |
||||
* Flask-Login (python-flask-login) |
||||
* psycopg2 (python-psycopg2) |
||||
* bcrypt (python-bcrypt) |
||||
|
||||
You'll have to configure PostgreSQL yourself and get a connection string that |
||||
fosspay can use. Then you can clone this repository to wherever you want to run |
||||
it from (I suggest making an unprivledged user account on the server you want to |
||||
host this on). |
||||
|
||||
### Configuration |
||||
|
||||
Copy config.ini.example to config.ini and edit it to your liking. Then, you can |
||||
run this command to try the site in development mode: |
||||
|
||||
python app.py |
||||
|
||||
[Click here](http://localhost:5000) to visit your donation site and further |
||||
instructions will be provided there. |
||||
|
||||
### Production Deployment |
||||
|
||||
To deploy this to production, copy the systemd unit from `contrib/` to your |
||||
server at `/etc/systemd/system/` (or whatever's appropriate for your distro). |
||||
Use `sytsemctl enable fosspay` and `systemctl start fosspay` to run the site on |
||||
`127.0.0.1:8000` (you can change this port by editing the unit file). You should |
||||
configure nginx to proxy through to fosspay from whatever other website you |
||||
already have. My nginx config is provided in `contrib/` for you to take a look |
||||
at - it proxies most requests to Github pages (my blog), and `/donate` to |
||||
fosspay. |
@ -0,0 +1,11 @@ |
||||
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) |
@ -0,0 +1,24 @@ |
||||
[dev] |
||||
# Change this to the actual location of your site |
||||
protocol=http |
||||
domain=localhost:5000 |
||||
# Change this value to something random and secret |
||||
secret-key=hello world |
||||
|
||||
# On the debug server, this lets you choose what to bind to |
||||
debug-host=0.0.0.0 |
||||
debug-port=5000 |
||||
|
||||
# Fill out these details with your mail server |
||||
smtp-host=mail.you.com |
||||
smtp-port=587 |
||||
smtp-user=you |
||||
smtp-password=password |
||||
smtp-from=donate@you.com |
||||
|
||||
# Your information |
||||
your_name=Joe Bloe |
||||
your_email=joe@bloe.com |
||||
|
||||
# SQL connection string |
||||
connection-string=postgresql://postgres@localhost/fosspay |
@ -0,0 +1,74 @@ |
||||
from flask import Flask, render_template, request, g, Response, redirect, url_for |
||||
from flask.ext.login import LoginManager, current_user |
||||
from jinja2 import FileSystemLoader, ChoiceLoader |
||||
|
||||
import sys |
||||
import os |
||||
import locale |
||||
|
||||
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"), |
||||
]) |
||||
|
||||
@login_manager.user_loader |
||||
def load_user(email): |
||||
return User.query.filter(User.email == email).first() |
||||
|
||||
login_manager.anonymous_user = lambda: None |
||||
|
||||
app.register_blueprint(html) |
||||
|
||||
try: |
||||
locale.setlocale(locale.LC_ALL, 'en_US') |
||||
except: |
||||
pass |
||||
|
||||
if not app.debug: |
||||
@app.errorhandler(500) |
||||
def handle_500(e): |
||||
# shit |
||||
try: |
||||
db.rollback() |
||||
db.close() |
||||
except: |
||||
# shit shit |
||||
print("We're very borked, letting init system kick us back up") |
||||
sys.exit(1) |
||||
return render_template("internal_error.html"), 500 |
||||
|
||||
@app.errorhandler(404) |
||||
def handle_404(e): |
||||
return render_template("not_found.html"), 404 |
||||
|
||||
@app.context_processor |
||||
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, |
||||
'debug': app.debug |
||||
} |
@ -0,0 +1,39 @@ |
||||
from flask import Blueprint, render_template, abort, request, redirect, session, url_for, send_file, Response |
||||
from flask.ext.login import current_user, login_user, logout_user |
||||
from fosspay.objects import * |
||||
from fosspay.database import db |
||||
from fosspay.common import * |
||||
from fosspay.config import _cfg, load_config |
||||
|
||||
import locale |
||||
|
||||
encoding = locale.getdefaultlocale()[1] |
||||
html = Blueprint('html', __name__, template_folder='../../templates') |
||||
|
||||
@html.route("/") |
||||
def index(): |
||||
if User.query.count() == 0: |
||||
load_config() |
||||
return render_template("setup.html") |
||||
return render_template("index.html") |
||||
|
||||
@html.route("/setup", methods=["POST"]) |
||||
def setup(): |
||||
if not User.query.count() == 0: |
||||
abort(400) |
||||
email = request.form.get("email") |
||||
password = request.form.get("password") |
||||
if not email or not password: |
||||
return redirect("/") # TODO: Tell them what they did wrong (i.e. being stupid) |
||||
user = User(email, password) |
||||
user.admin = True |
||||
db.add(user) |
||||
db.commit() |
||||
login_user(user) |
||||
return redirect("/admin?first-run=1") |
||||
|
||||
@html.route("/admin") |
||||
@adminrequired |
||||
def admin(): |
||||
first=bool(request.args.get("first-run")) |
||||
return render_template("admin.html", first=first) |
@ -0,0 +1,104 @@ |
||||
from flask import session, jsonify, redirect, request, Response, abort |
||||
from flask.ext.login import current_user |
||||
from werkzeug.utils import secure_filename |
||||
from functools import wraps |
||||
from fosspay.objects import User |
||||
from fosspay.database import db, Base |
||||
from fosspay.config import _cfg |
||||
|
||||
import json |
||||
import urllib |
||||
import requests |
||||
import xml.etree.ElementTree as ET |
||||
import hashlib |
||||
|
||||
def firstparagraph(text): |
||||
try: |
||||
para = text.index("\n\n") |
||||
return text[:para + 2] |
||||
except: |
||||
try: |
||||
para = text.index("\r\n\r\n") |
||||
return text[:para + 4] |
||||
except: |
||||
return text |
||||
|
||||
def with_session(f): |
||||
@wraps(f) |
||||
def go(*args, **kw): |
||||
try: |
||||
ret = f(*args, **kw) |
||||
db.commit() |
||||
return ret |
||||
except: |
||||
db.rollback() |
||||
db.close() |
||||
raise |
||||
return go |
||||
|
||||
def loginrequired(f): |
||||
@wraps(f) |
||||
def wrapper(*args, **kwargs): |
||||
if not current_user: |
||||
return redirect("/login?return_to=" + urllib.parse.quote_plus(request.url)) |
||||
else: |
||||
return f(*args, **kwargs) |
||||
return wrapper |
||||
|
||||
def adminrequired(f): |
||||
@wraps(f) |
||||
def wrapper(*args, **kwargs): |
||||
if not current_user: |
||||
return redirect("/login?return_to=" + urllib.parse.quote_plus(request.url)) |
||||
else: |
||||
if not current_user.admin: |
||||
abort(401) |
||||
return f(*args, **kwargs) |
||||
return wrapper |
||||
|
||||
def json_output(f): |
||||
@wraps(f) |
||||
def wrapper(*args, **kwargs): |
||||
def jsonify_wrap(obj): |
||||
jsonification = json.dumps(obj) |
||||
return Response(jsonification, mimetype='application/json') |
||||
|
||||
result = f(*args, **kwargs) |
||||
if isinstance(result, tuple): |
||||
return jsonify_wrap(result[0]), result[1] |
||||
if isinstance(result, dict): |
||||
return jsonify_wrap(result) |
||||
if isinstance(result, list): |
||||
return jsonify_wrap(result) |
||||
|
||||
# This is a fully fleshed out response, return it immediately |
||||
return result |
||||
|
||||
return wrapper |
||||
|
||||
def cors(f): |
||||
@wraps(f) |
||||
def wrapper(*args, **kwargs): |
||||
res = f(*args, **kwargs) |
||||
if request.headers.get('x-cors-status', False): |
||||
if isinstance(res, tuple): |
||||
json_text = res[0].data |
||||
code = res[1] |
||||
else: |
||||
json_text = res.data |
||||
code = 200 |
||||
|
||||
o = json.loads(json_text) |
||||
o['x-status'] = code |
||||
|
||||
return jsonify(o) |
||||
|
||||
return res |
||||
|
||||
return wrapper |
||||
|
||||
def file_link(path): |
||||
return _cfg("protocol") + "://" + _cfg("domain") + "/" + path |
||||
|
||||
def disown_link(path): |
||||
return _cfg("protocol") + "://" + _cfg("domain") + "/disown?filename=" + path |
@ -0,0 +1,33 @@ |
||||
import logging |
||||
|
||||
try: |
||||
from configparser import ConfigParser |
||||
except ImportError: |
||||
# Python 2 support |
||||
from ConfigParser import ConfigParser |
||||
|
||||
logger = logging.getLogger("fosspay") |
||||
logger.setLevel(logging.DEBUG) |
||||
|
||||
sh = logging.StreamHandler() |
||||
sh.setLevel(logging.DEBUG) |
||||
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") |
||||
sh.setFormatter(formatter) |
||||
|
||||
logger.addHandler(sh) |
||||
|
||||
# scss logger |
||||
logging.getLogger("scss").addHandler(sh) |
||||
|
||||
env = 'dev' |
||||
config = None |
||||
|
||||
def load_config(): |
||||
global config |
||||
config = ConfigParser() |
||||
config.readfp(open('config.ini')) |
||||
|
||||
load_config() |
||||
|
||||
_cfg = lambda k: config.get(env, k) |
||||
_cfgi = lambda k: int(_cfg(k)) |
@ -0,0 +1,14 @@ |
||||
from sqlalchemy import create_engine |
||||
from sqlalchemy.orm import scoped_session, sessionmaker |
||||
from sqlalchemy.ext.declarative import declarative_base |
||||
|
||||
from .config import _cfg, _cfgi |
||||
engine = create_engine(_cfg('connection-string')) |
||||
db = scoped_session(sessionmaker(autocommit=False, autoflush=False, bind=engine)) |
||||
|
||||
Base = declarative_base() |
||||
Base.query = db.query_property() |
||||
|
||||
def init_db(): |
||||
import fosspay.objects |
||||
Base.metadata.create_all(bind=engine) |
@ -0,0 +1,19 @@ |
||||
def makeMask(n): |
||||
"return a mask of n bits as a long integer" |
||||
return (2 << n - 1) - 1 |
||||
|
||||
|
||||
def dottedQuadToNum(ip): |
||||
"convert decimal dotted quad string to long integer" |
||||
parts = ip.split(".") |
||||
return int(parts[0]) | (int(parts[1]) << 8) | (int(parts[2]) << 16) | (int(parts[3]) << 24) |
||||
|
||||
|
||||
def networkMask(ip, bits): |
||||
"Convert a network address to a long integer" |
||||
return dottedQuadToNum(ip) & makeMask(bits) |
||||
|
||||
|
||||
def addressInNetwork(ip, net): |
||||
"Is an address in a network" |
||||
return ip & net == net |
@ -0,0 +1,42 @@ |
||||
from sqlalchemy import Column, Integer, String, Unicode, Boolean, DateTime |
||||
from sqlalchemy import ForeignKey, Table, UnicodeText, Text, text |
||||
from sqlalchemy.orm import relationship, backref |
||||
from .database import Base |
||||
|
||||
from datetime import datetime |
||||
import bcrypt |
||||
import os |
||||
import hashlib |
||||
|
||||
class User(Base): |
||||
__tablename__ = 'user' |
||||
id = Column(Integer, primary_key = True) |
||||
email = Column(String(256), nullable = False, index = True) |
||||
admin = Column(Boolean()) |
||||
password = Column(String) |
||||
created = Column(DateTime) |
||||
passwordReset = Column(String(128)) |
||||
passwordResetExpiry = Column(DateTime) |
||||
|
||||
def set_password(self, password): |
||||
self.password = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt()).decode("utf-8") |
||||
|
||||
def __init__(self, email, password): |
||||
self.email = email |
||||
self.admin = False |
||||
self.created = datetime.now() |
||||
self.set_password(password) |
||||
|
||||
def __repr__(self): |
||||
return '<User %r>' % self.username |
||||
|
||||
# Flask.Login stuff |
||||
# We don't use most of these features |
||||
def is_authenticated(self): |
||||
return True |
||||
def is_active(self): |
||||
return True |
||||
def is_anonymous(self): |
||||
return False |
||||
def get_id(self): |
||||
return self.email |
@ -0,0 +1,5 @@ |
||||
stripe |
||||
Flask |
||||
Jinja2 |
||||
Flask-Misaka |
||||
gunicorn |
@ -0,0 +1,64 @@ |
||||
{% extends "layout.html" %} |
||||
{% block body %} |
||||
<h1>Fosspay Admin</h1> |
||||
{% if first %} |
||||
<div class="well"> |
||||
<p> |
||||
You're set up and ready to go! This is your admin panel. |
||||
Yeah, it's not pretty. Next steps: |
||||
</p> |
||||
<ol> |
||||
<li> |
||||
Add some projects. Donors can tell you which project they want to support |
||||
when they donate. |
||||
</li> |
||||
<li> |
||||
Customize the look & feel. Look at the contents of the <code>templates</code> |
||||
directory - you can copy and paste any of these templates into the |
||||
<code>overrides</code> directory and change it to suit your needs. |
||||
</li> |
||||
<li> |
||||
<a href="https://drewdevault.com/donate?project=fosspay">Donate to fosspay upstream?</a> |
||||
</li> |
||||
<li> |
||||
<a href="https://github.com/SirCmpwn/fosspay">Contribute code to fosspay upstream?</a> |
||||
</li> |
||||
</ol> |
||||
</div> |
||||
{% endif %} |
||||
<h2>Projects</h2> |
||||
<div class="row"> |
||||
<div class="col-md-6"> |
||||
<table class="table"> |
||||
<thead> |
||||
<tr> |
||||
<th>Project Name</th> |
||||
<th>One-off donations</th> |
||||
<th>Recurring donations</th> |
||||
</tr> |
||||
</thead> |
||||
</table> |
||||
</div> |
||||
<div class="col-md-6"> |
||||
<h4>Add Project</h4> |
||||
<form method="POST" action="/create-project"> |
||||
<div class="form-group"> |
||||
<input class="form-control" type="text" placeholder="Project name" name="name" /> |
||||
</div> |
||||
<input type="submit" value="Add" /> |
||||
</form> |
||||
</div> |
||||
</div> |
||||
<h2>Donation History</h2> |
||||
<table class="table"> |
||||
<thead> |
||||
<tr> |
||||
<th>Email</th> |
||||
<th>Project</th> |
||||
<th>Comment</th> |
||||
<th>Amount</th> |
||||
<th style="width: 10%">Recurring</th> |
||||
</tr> |
||||
</thead> |
||||
</table> |
||||
{% endblock %} |
@ -0,0 +1,14 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
{% 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" /> |
||||
</head> |
||||
<body> |
||||
<div class="container"> |
||||
{% block body %}{% endblock %} |
||||
</div> |
||||
</body> |
||||
</html> |
@ -0,0 +1,73 @@ |
||||
{% extends "layout.html" %} |
||||
{% block body %} |
||||
<h1>FossPay Setup</h1> |
||||
<p>Congrats! You have FossPay up and running.</p> |
||||
|
||||
<h2>config.ini</h2> |
||||
<ul class="list-unstyled"> |
||||
<li> |
||||
{% if _cfg("secret-key") == "hello world" %} |
||||
<span class="glyphicon glyphicon-remove text-danger"></span> |
||||
You need to change the secret key to something other than "hello world". |
||||
{% else %} |
||||
<span class="glyphicon glyphicon-ok text-success"></span> |
||||
Your secret key looks good. |
||||
{% endif %} |
||||
</li> |
||||
|
||||
<li> |
||||
{% if _cfg("domain") == "localhost:5000" %} |
||||
<span class="glyphicon glyphicon-remove text-danger"></span> |
||||
You should change your domain to something other than localhost. |
||||
{% else %} |
||||
<span class="glyphicon glyphicon-ok text-success"></span> |
||||
Your domain is set to "{{_cfg("domain")}}". |
||||
{% endif %} |
||||
</li> |
||||
|
||||
<li> |
||||
{% if _cfg("protocol") != "https" %} |
||||
<span class="glyphicon glyphicon-remove text-danger"></span> |
||||
Stripe requires your website to use HTTPS. |
||||
{% else %} |
||||
<span class="glyphicon glyphicon-ok text-success"></span> |
||||
Stripe requires your website to use HTTPS. |
||||
{% endif %} |
||||
</li> |
||||
|
||||
<li> |
||||
{% if not _cfg("smtp-host") %} |
||||
<span class="glyphicon glyphicon-remove text-danger"></span> |
||||
You should configure an SMTP server to send emails with. |
||||
{% else %} |
||||
<span class="glyphicon glyphicon-ok text-success"></span> |
||||
Your email configuration looks good. |
||||
{% endif %} |
||||
</li> |
||||
|
||||
<li> |
||||
{% if not _cfg("stripe-secret") or not _cfg("stripe-publish") %} |
||||
<span class="glyphicon glyphicon-remove text-danger"></span> |
||||
Your Stripe API keys are not in your config file. |
||||
{% else %} |
||||
<span class="glyphicon glyphicon-ok text-success"></span> |
||||
Your Stripe API keys look good. |
||||
{% endif %} |
||||
</li> |
||||
</ul> |
||||
<p>You can make changes and refresh this page if you like.</p> |
||||
|
||||
<h2>Admin Account</h2> |
||||
<p>Enter your details for the admin account:</p> |
||||
<form class="form" action="/setup" method="POST"> |
||||
<div class="form-group"> |
||||
<input type="text" class="form-control" name="email" |
||||
placeholder="Email" value="{{_cfg("your-email")}}" /> |
||||
</div> |
||||
<div class="form-group"> |
||||
<input type="password" class="form-control" name="password" placeholder="Password" /> |
||||
</div> |
||||
<input type="submit" value="Continue" class="btn btn-primary" /> |
||||
</form> |
||||
|
||||
{% endblock %} |
Loading…
Reference in new issue