@ -0,0 +1,28 @@ | |||||
from flask import Flask | |||||
from flask_bootstrap import Bootstrap | |||||
from flask_mail import Mail | |||||
from flask_moment import Moment | |||||
from flask_sqlalchemy import SQLAlchemy | |||||
from config import config | |||||
bootstrap = Bootstrap() | |||||
mail = Mail() | |||||
moment = Moment() | |||||
db = SQLAlchemy() | |||||
def create_app(config_name): | |||||
app = Flask(__name__) | |||||
app.config.from_object(config[config_name]) | |||||
config[config_name].init_app(app) | |||||
bootstrap.init_app(app) | |||||
mail.init_app(app) | |||||
moment.init_app(app) | |||||
db.init_app(app) | |||||
from .main import main as main_blueprint | |||||
app.register_blueprint(main_blueprint) | |||||
return app |
@ -0,0 +1,20 @@ | |||||
from threading import Thread | |||||
from flask import current_app, render_template | |||||
from flask_mail import Message | |||||
from . import mail | |||||
def send_async_email(app, msg): | |||||
with app.app_context(): | |||||
mail.send(msg) | |||||
def send_email(to, subject, template, **kwargs): | |||||
app = current_app._get_current_object() | |||||
msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + ' ' + subject, | |||||
sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to]) | |||||
msg.body = render_template(template + '.txt', **kwargs) | |||||
msg.html = render_template(template + '.html', **kwargs) | |||||
thr = Thread(target=send_async_email, args=[app, msg]) | |||||
thr.start() | |||||
return thr |
@ -0,0 +1,7 @@ | |||||
from flask import Blueprint | |||||
main = Blueprint('main', __name__) | |||||
from . import views, errors |
@ -0,0 +1,12 @@ | |||||
from flask import render_template | |||||
from . import main | |||||
@main.app_errorhandler(404) | |||||
def page_not_found(e): | |||||
return render_template('404.html'), 404 | |||||
@main.app_errorhandler(500) | |||||
def internal_server_error(e): | |||||
return render_template('500.html'), 500 |
@ -0,0 +1,8 @@ | |||||
from flask_wtf import FlaskForm | |||||
from wtforms import StringField, SubmitField | |||||
from wtforms.validators import DataRequired | |||||
class NameForm(FlaskForm): | |||||
name = StringField('What is your name?', validators=[DataRequired()]) | |||||
submit = SubmitField('Submit') |
@ -0,0 +1,29 @@ | |||||
from flask import render_template, session, redirect, url_for, current_app | |||||
from .. import db | |||||
from ..models import User | |||||
from ..email import send_email | |||||
from . import main | |||||
from .forms import NameForm | |||||
@main.route('/', methods=['GET', 'POST']) | |||||
def index(): | |||||
form = NameForm() | |||||
if form.validate_on_submit(): | |||||
user = User.query.filter_by(username=form.name.data).first() | |||||
if user is None: | |||||
user = User(username=form.name.data) | |||||
db.session.add(user) | |||||
db.session.commit() | |||||
session['known'] = False | |||||
if current_app.config['FLASKY_ADMIN']: | |||||
send_email(current_app.config['FLASKY_ADMIN'], 'New user', | |||||
'mail/new_user', user=user) | |||||
else: | |||||
session['known'] = True | |||||
session['name'] = form.name.data | |||||
form.name.data = '' | |||||
return redirect(url_for('.index')) | |||||
return render_template('index.html', | |||||
form=form, name=session.get('name'), | |||||
known=session.get('known', False)) |
@ -0,0 +1,21 @@ | |||||
from . import db | |||||
class Role(db.Model): | |||||
__tablename__ = 'roles' | |||||
id = db.Column(db.Integer, primary_key=True) | |||||
name = db.Column(db.String(64), unique=True) | |||||
users = db.relationship('User', backref='role', lazy='dynamic') | |||||
def __repr__(self): | |||||
return '<Role %r>' % self.name | |||||
class User(db.Model): | |||||
__tablename__ = 'users' | |||||
id = db.Column(db.Integer, primary_key=True) | |||||
username = db.Column(db.String(64), unique=True, index=True) | |||||
role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) | |||||
def __repr__(self): | |||||
return '<User %r>' % self.username |
@ -0,0 +1,46 @@ | |||||
import os | |||||
basedir = os.path.abspath(os.path.dirname(__file__)) | |||||
class Config: | |||||
SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string' | |||||
MAIL_SERVER = os.environ.get('MAIL_SERVER', 'smtp.strato.de') | |||||
MAIL_PORT = int(os.environ.get('MAIL_PORT', '587')) | |||||
MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true').lower() in \ | |||||
['true', 'on', '1'] | |||||
MAIL_USERNAME = os.environ.get('MAIL_USERNAME') | |||||
MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD') | |||||
FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]' | |||||
FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>' | |||||
FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN') | |||||
SQLALCHEMY_TRACK_MODIFICATIONS = False | |||||
@staticmethod | |||||
def init_app(app): | |||||
pass | |||||
class DevelopmentConfig(Config): | |||||
DEBUG = True | |||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \ | |||||
'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite') | |||||
class TestingConfig(Config): | |||||
TESTING = True | |||||
SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \ | |||||
'sqlite://' | |||||
class ProductionConfig(Config): | |||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \ | |||||
'sqlite:///' + os.path.join(basedir, 'data.sqlite') | |||||
config = { | |||||
'development': DevelopmentConfig, | |||||
'testing': TestingConfig, | |||||
'production': ProductionConfig, | |||||
'default': DevelopmentConfig | |||||
} |
@ -0,0 +1,21 @@ | |||||
import os | |||||
from flask_migrate import Migrate | |||||
from app import create_app, db | |||||
from app.models import User, Role | |||||
app = create_app(os.getenv('FLASK_CONFIG') or 'default') | |||||
migrate = Migrate(app, db) | |||||
@app.shell_context_processor | |||||
def make_shell_context(): | |||||
return dict(db=db, User=User, Role=Role) | |||||
@app.cli.command() | |||||
def test(): | |||||
"""Run the unit tests.""" | |||||
import unittest | |||||
tests = unittest.TestLoader().discover('tests') | |||||
unittest.TextTestRunner(verbosity=2).run(tests) |
@ -1,111 +0,0 @@ | |||||
import os | |||||
from threading import Thread | |||||
from flask import Flask, render_template, session, redirect, url_for | |||||
from flask_bootstrap import Bootstrap | |||||
from flask_moment import Moment | |||||
from flask_wtf import FlaskForm | |||||
from wtforms import StringField, SubmitField | |||||
from wtforms.validators import DataRequired | |||||
from flask_sqlalchemy import SQLAlchemy | |||||
from flask_migrate import Migrate | |||||
from flask_mail import Mail, Message | |||||
basedir = os.path.abspath(os.path.dirname(__file__)) | |||||
app = Flask(__name__) | |||||
app.config['SECRET_KEY'] = 'hard to guess string' | |||||
app.config['SQLALCHEMY_DATABASE_URI'] = \ | |||||
'sqlite:///' + os.path.join(basedir, 'data.sqlite') | |||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False | |||||
app.config['MAIL_SERVER'] = 'smtp.strato.com' | |||||
app.config['MAIL_PORT'] = 587 | |||||
app.config['MAIL_USE_TLS'] = True | |||||
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME') | |||||
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD') | |||||
app.config['FLASKY_MAIL_SUBJECT_PREFIX'] = '[Flasky]' | |||||
app.config['FLASKY_MAIL_SENDER'] = 'Flasky Admin <flasky@example.com>' | |||||
app.config['FLASKY_ADMIN'] = os.environ.get('FLASKY_ADMIN') | |||||
bootstrap = Bootstrap(app) | |||||
moment = Moment(app) | |||||
db = SQLAlchemy(app) | |||||
migrate = Migrate(app, db) | |||||
mail = Mail(app) | |||||
class Role(db.Model): | |||||
__tablename__ = 'roles' | |||||
id = db.Column(db.Integer, primary_key=True) | |||||
name = db.Column(db.String(64), unique=True) | |||||
users = db.relationship('User', backref='role', lazy='dynamic') | |||||
def __repr__(self): | |||||
return '<Role %r>' % self.name | |||||
class User(db.Model): | |||||
__tablename__ = 'users' | |||||
id = db.Column(db.Integer, primary_key=True) | |||||
username = db.Column(db.String(64), unique=True, index=True) | |||||
role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) | |||||
def __repr__(self): | |||||
return '<User %r>' % self.username | |||||
def send_async_email(app, msg): | |||||
with app.app_context(): | |||||
mail.send(msg) | |||||
def send_email(to, subject, template, **kwargs): | |||||
msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + subject, | |||||
sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to]) | |||||
msg.body = render_template(template + '.txt', **kwargs) | |||||
msg.html = render_template(template + '.html', **kwargs) | |||||
thr = Thread(target=send_async_email, args=[app, msg]) | |||||
thr.start() | |||||
return thr | |||||
class NameForm(FlaskForm): | |||||
name = StringField('What is your name?', validators=[DataRequired()]) | |||||
submit = SubmitField('Submit') | |||||
@app.shell_context_processor | |||||
def make_shell_context(): | |||||
return dict(db=db, User=User, Role=Role) | |||||
@app.errorhandler(404) | |||||
def page_not_found(e): | |||||
return render_template('404.html'), 404 | |||||
@app.errorhandler(500) | |||||
def internal_server_error(e): | |||||
return render_template('500.html'), 500 | |||||
@app.route('/', methods=['GET', 'POST']) | |||||
def index(): | |||||
form = NameForm() | |||||
if form.validate_on_submit(): | |||||
user = User.query.filter_by(username=form.name.data).first() | |||||
if user is None: | |||||
user = User(username=form.name.data) | |||||
db.session.add(user) | |||||
db.session.commit() | |||||
session['known'] = False | |||||
if app.config['FLASKY_ADMIN']: | |||||
send_email(app.config['FLASKY_ADMIN'], ' New user', | |||||
'mail/new_user', user=user) | |||||
else: | |||||
session['known'] = True | |||||
session['name'] = form.name.data | |||||
form.name.data = '' | |||||
return redirect(url_for('index')) | |||||
return render_template('index.html', form=form, name=session.get('name'), | |||||
known=session.get('known', False)) |
@ -0,0 +1,22 @@ | |||||
alembic==1.0.1 | |||||
blinker==1.4 | |||||
Click==7.0 | |||||
dominate==2.3.4 | |||||
Flask==1.0.2 | |||||
Flask-Bootstrap==3.3.7.1 | |||||
Flask-Mail==0.9.1 | |||||
Flask-Migrate==2.2.1 | |||||
Flask-Moment==0.6.0 | |||||
Flask-SQLAlchemy==2.3.2 | |||||
Flask-WTF==0.14.2 | |||||
itsdangerous==0.24 | |||||
Jinja2==2.10 | |||||
Mako==1.0.7 | |||||
MarkupSafe==1.0 | |||||
python-dateutil==2.7.3 | |||||
python-editor==1.0.3 | |||||
six==1.11.0 | |||||
SQLAlchemy==1.2.12 | |||||
visitor==0.1.3 | |||||
Werkzeug==0.14.1 | |||||
WTForms==2.2.1 |
@ -0,0 +1,22 @@ | |||||
import unittest | |||||
from flask import current_app | |||||
from app import create_app, db | |||||
class BasicTestCase(unittest.TestCase): | |||||
def setUp(self): | |||||
self.app = create_app('testing') | |||||
self.app_context = self.app.app_context() | |||||
self.app_context.push() | |||||
db.create_all() | |||||
def tearDown(self): | |||||
db.session.remove() | |||||
db.drop_all() | |||||
self.app_context.pop() | |||||
def test_app_exists(self): | |||||
self.assertFalse(current_app is None) | |||||
def test_app_is_testing(self): | |||||
self.assertTrue(current_app.config['TESTING']) |