parent
5b309831ec
commit
025589ee76
63 changed files with 3784 additions and 3459 deletions
|
|
@ -8,14 +8,14 @@ def create_app(test_config=None):
|
|||
app = Flask(__name__, instance_relative_config=True)
|
||||
app.config.from_mapping(
|
||||
# a default secret that should be overridden by instance config
|
||||
SECRET_KEY='dev',
|
||||
SECRET_KEY="dev",
|
||||
# store the database in the instance folder
|
||||
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
|
||||
DATABASE=os.path.join(app.instance_path, "flaskr.sqlite"),
|
||||
)
|
||||
|
||||
if test_config is None:
|
||||
# load the instance config, if it exists, when not testing
|
||||
app.config.from_pyfile('config.py', silent=True)
|
||||
app.config.from_pyfile("config.py", silent=True)
|
||||
else:
|
||||
# load the test config if passed in
|
||||
app.config.update(test_config)
|
||||
|
|
@ -26,16 +26,18 @@ def create_app(test_config=None):
|
|||
except OSError:
|
||||
pass
|
||||
|
||||
@app.route('/hello')
|
||||
@app.route("/hello")
|
||||
def hello():
|
||||
return 'Hello, World!'
|
||||
return "Hello, World!"
|
||||
|
||||
# register the database commands
|
||||
from flaskr import db
|
||||
|
||||
db.init_app(app)
|
||||
|
||||
# apply the blueprints to the app
|
||||
from flaskr import auth, blog
|
||||
|
||||
app.register_blueprint(auth.bp)
|
||||
app.register_blueprint(blog.bp)
|
||||
|
||||
|
|
@ -43,6 +45,6 @@ def create_app(test_config=None):
|
|||
# in another app, you might define a separate main index here with
|
||||
# app.route, while giving the blog blueprint a url_prefix, but for
|
||||
# the tutorial the blog will be the main index
|
||||
app.add_url_rule('/', endpoint='index')
|
||||
app.add_url_rule("/", endpoint="index")
|
||||
|
||||
return app
|
||||
|
|
|
|||
|
|
@ -1,21 +1,29 @@
|
|||
import functools
|
||||
|
||||
from flask import (
|
||||
Blueprint, flash, g, redirect, render_template, request, session, url_for
|
||||
Blueprint,
|
||||
flash,
|
||||
g,
|
||||
redirect,
|
||||
render_template,
|
||||
request,
|
||||
session,
|
||||
url_for,
|
||||
)
|
||||
from werkzeug.security import check_password_hash, generate_password_hash
|
||||
|
||||
from flaskr.db import get_db
|
||||
|
||||
bp = Blueprint('auth', __name__, url_prefix='/auth')
|
||||
bp = Blueprint("auth", __name__, url_prefix="/auth")
|
||||
|
||||
|
||||
def login_required(view):
|
||||
"""View decorator that redirects anonymous users to the login page."""
|
||||
|
||||
@functools.wraps(view)
|
||||
def wrapped_view(**kwargs):
|
||||
if g.user is None:
|
||||
return redirect(url_for('auth.login'))
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
return view(**kwargs)
|
||||
|
||||
|
|
@ -26,83 +34,84 @@ def login_required(view):
|
|||
def load_logged_in_user():
|
||||
"""If a user id is stored in the session, load the user object from
|
||||
the database into ``g.user``."""
|
||||
user_id = session.get('user_id')
|
||||
user_id = session.get("user_id")
|
||||
|
||||
if user_id is None:
|
||||
g.user = None
|
||||
else:
|
||||
g.user = get_db().execute(
|
||||
'SELECT * FROM user WHERE id = ?', (user_id,)
|
||||
).fetchone()
|
||||
g.user = (
|
||||
get_db().execute("SELECT * FROM user WHERE id = ?", (user_id,)).fetchone()
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/register', methods=('GET', 'POST'))
|
||||
@bp.route("/register", methods=("GET", "POST"))
|
||||
def register():
|
||||
"""Register a new user.
|
||||
|
||||
Validates that the username is not already taken. Hashes the
|
||||
password for security.
|
||||
"""
|
||||
if request.method == 'POST':
|
||||
username = request.form['username']
|
||||
password = request.form['password']
|
||||
if request.method == "POST":
|
||||
username = request.form["username"]
|
||||
password = request.form["password"]
|
||||
db = get_db()
|
||||
error = None
|
||||
|
||||
if not username:
|
||||
error = 'Username is required.'
|
||||
error = "Username is required."
|
||||
elif not password:
|
||||
error = 'Password is required.'
|
||||
elif db.execute(
|
||||
'SELECT id FROM user WHERE username = ?', (username,)
|
||||
).fetchone() is not None:
|
||||
error = 'User {0} is already registered.'.format(username)
|
||||
error = "Password is required."
|
||||
elif (
|
||||
db.execute("SELECT id FROM user WHERE username = ?", (username,)).fetchone()
|
||||
is not None
|
||||
):
|
||||
error = "User {0} is already registered.".format(username)
|
||||
|
||||
if error is None:
|
||||
# the name is available, store it in the database and go to
|
||||
# the login page
|
||||
db.execute(
|
||||
'INSERT INTO user (username, password) VALUES (?, ?)',
|
||||
(username, generate_password_hash(password))
|
||||
"INSERT INTO user (username, password) VALUES (?, ?)",
|
||||
(username, generate_password_hash(password)),
|
||||
)
|
||||
db.commit()
|
||||
return redirect(url_for('auth.login'))
|
||||
return redirect(url_for("auth.login"))
|
||||
|
||||
flash(error)
|
||||
|
||||
return render_template('auth/register.html')
|
||||
return render_template("auth/register.html")
|
||||
|
||||
|
||||
@bp.route('/login', methods=('GET', 'POST'))
|
||||
@bp.route("/login", methods=("GET", "POST"))
|
||||
def login():
|
||||
"""Log in a registered user by adding the user id to the session."""
|
||||
if request.method == 'POST':
|
||||
username = request.form['username']
|
||||
password = request.form['password']
|
||||
if request.method == "POST":
|
||||
username = request.form["username"]
|
||||
password = request.form["password"]
|
||||
db = get_db()
|
||||
error = None
|
||||
user = db.execute(
|
||||
'SELECT * FROM user WHERE username = ?', (username,)
|
||||
"SELECT * FROM user WHERE username = ?", (username,)
|
||||
).fetchone()
|
||||
|
||||
if user is None:
|
||||
error = 'Incorrect username.'
|
||||
elif not check_password_hash(user['password'], password):
|
||||
error = 'Incorrect password.'
|
||||
error = "Incorrect username."
|
||||
elif not check_password_hash(user["password"], password):
|
||||
error = "Incorrect password."
|
||||
|
||||
if error is None:
|
||||
# store the user id in a new session and return to the index
|
||||
session.clear()
|
||||
session['user_id'] = user['id']
|
||||
return redirect(url_for('index'))
|
||||
session["user_id"] = user["id"]
|
||||
return redirect(url_for("index"))
|
||||
|
||||
flash(error)
|
||||
|
||||
return render_template('auth/login.html')
|
||||
return render_template("auth/login.html")
|
||||
|
||||
|
||||
@bp.route('/logout')
|
||||
@bp.route("/logout")
|
||||
def logout():
|
||||
"""Clear the current session, including the stored user id."""
|
||||
session.clear()
|
||||
return redirect(url_for('index'))
|
||||
return redirect(url_for("index"))
|
||||
|
|
|
|||
|
|
@ -1,24 +1,22 @@
|
|||
from flask import (
|
||||
Blueprint, flash, g, redirect, render_template, request, url_for
|
||||
)
|
||||
from flask import Blueprint, flash, g, redirect, render_template, request, url_for
|
||||
from werkzeug.exceptions import abort
|
||||
|
||||
from flaskr.auth import login_required
|
||||
from flaskr.db import get_db
|
||||
|
||||
bp = Blueprint('blog', __name__)
|
||||
bp = Blueprint("blog", __name__)
|
||||
|
||||
|
||||
@bp.route('/')
|
||||
@bp.route("/")
|
||||
def index():
|
||||
"""Show all the posts, most recent first."""
|
||||
db = get_db()
|
||||
posts = db.execute(
|
||||
'SELECT p.id, title, body, created, author_id, username'
|
||||
' FROM post p JOIN user u ON p.author_id = u.id'
|
||||
' ORDER BY created DESC'
|
||||
"SELECT p.id, title, body, created, author_id, username"
|
||||
" FROM post p JOIN user u ON p.author_id = u.id"
|
||||
" ORDER BY created DESC"
|
||||
).fetchall()
|
||||
return render_template('blog/index.html', posts=posts)
|
||||
return render_template("blog/index.html", posts=posts)
|
||||
|
||||
|
||||
def get_post(id, check_author=True):
|
||||
|
|
@ -33,78 +31,80 @@ def get_post(id, check_author=True):
|
|||
:raise 404: if a post with the given id doesn't exist
|
||||
:raise 403: if the current user isn't the author
|
||||
"""
|
||||
post = get_db().execute(
|
||||
'SELECT p.id, title, body, created, author_id, username'
|
||||
' FROM post p JOIN user u ON p.author_id = u.id'
|
||||
' WHERE p.id = ?',
|
||||
(id,)
|
||||
).fetchone()
|
||||
post = (
|
||||
get_db()
|
||||
.execute(
|
||||
"SELECT p.id, title, body, created, author_id, username"
|
||||
" FROM post p JOIN user u ON p.author_id = u.id"
|
||||
" WHERE p.id = ?",
|
||||
(id,),
|
||||
)
|
||||
.fetchone()
|
||||
)
|
||||
|
||||
if post is None:
|
||||
abort(404, "Post id {0} doesn't exist.".format(id))
|
||||
|
||||
if check_author and post['author_id'] != g.user['id']:
|
||||
if check_author and post["author_id"] != g.user["id"]:
|
||||
abort(403)
|
||||
|
||||
return post
|
||||
|
||||
|
||||
@bp.route('/create', methods=('GET', 'POST'))
|
||||
@bp.route("/create", methods=("GET", "POST"))
|
||||
@login_required
|
||||
def create():
|
||||
"""Create a new post for the current user."""
|
||||
if request.method == 'POST':
|
||||
title = request.form['title']
|
||||
body = request.form['body']
|
||||
if request.method == "POST":
|
||||
title = request.form["title"]
|
||||
body = request.form["body"]
|
||||
error = None
|
||||
|
||||
if not title:
|
||||
error = 'Title is required.'
|
||||
error = "Title is required."
|
||||
|
||||
if error is not None:
|
||||
flash(error)
|
||||
else:
|
||||
db = get_db()
|
||||
db.execute(
|
||||
'INSERT INTO post (title, body, author_id)'
|
||||
' VALUES (?, ?, ?)',
|
||||
(title, body, g.user['id'])
|
||||
"INSERT INTO post (title, body, author_id)" " VALUES (?, ?, ?)",
|
||||
(title, body, g.user["id"]),
|
||||
)
|
||||
db.commit()
|
||||
return redirect(url_for('blog.index'))
|
||||
return redirect(url_for("blog.index"))
|
||||
|
||||
return render_template('blog/create.html')
|
||||
return render_template("blog/create.html")
|
||||
|
||||
|
||||
@bp.route('/<int:id>/update', methods=('GET', 'POST'))
|
||||
@bp.route("/<int:id>/update", methods=("GET", "POST"))
|
||||
@login_required
|
||||
def update(id):
|
||||
"""Update a post if the current user is the author."""
|
||||
post = get_post(id)
|
||||
|
||||
if request.method == 'POST':
|
||||
title = request.form['title']
|
||||
body = request.form['body']
|
||||
if request.method == "POST":
|
||||
title = request.form["title"]
|
||||
body = request.form["body"]
|
||||
error = None
|
||||
|
||||
if not title:
|
||||
error = 'Title is required.'
|
||||
error = "Title is required."
|
||||
|
||||
if error is not None:
|
||||
flash(error)
|
||||
else:
|
||||
db = get_db()
|
||||
db.execute(
|
||||
'UPDATE post SET title = ?, body = ? WHERE id = ?',
|
||||
(title, body, id)
|
||||
"UPDATE post SET title = ?, body = ? WHERE id = ?", (title, body, id)
|
||||
)
|
||||
db.commit()
|
||||
return redirect(url_for('blog.index'))
|
||||
return redirect(url_for("blog.index"))
|
||||
|
||||
return render_template('blog/update.html', post=post)
|
||||
return render_template("blog/update.html", post=post)
|
||||
|
||||
|
||||
@bp.route('/<int:id>/delete', methods=('POST',))
|
||||
@bp.route("/<int:id>/delete", methods=("POST",))
|
||||
@login_required
|
||||
def delete(id):
|
||||
"""Delete a post.
|
||||
|
|
@ -114,6 +114,6 @@ def delete(id):
|
|||
"""
|
||||
get_post(id)
|
||||
db = get_db()
|
||||
db.execute('DELETE FROM post WHERE id = ?', (id,))
|
||||
db.execute("DELETE FROM post WHERE id = ?", (id,))
|
||||
db.commit()
|
||||
return redirect(url_for('blog.index'))
|
||||
return redirect(url_for("blog.index"))
|
||||
|
|
|
|||
|
|
@ -10,10 +10,9 @@ def get_db():
|
|||
is unique for each request and will be reused if this is called
|
||||
again.
|
||||
"""
|
||||
if 'db' not in g:
|
||||
if "db" not in g:
|
||||
g.db = sqlite3.connect(
|
||||
current_app.config['DATABASE'],
|
||||
detect_types=sqlite3.PARSE_DECLTYPES
|
||||
current_app.config["DATABASE"], detect_types=sqlite3.PARSE_DECLTYPES
|
||||
)
|
||||
g.db.row_factory = sqlite3.Row
|
||||
|
||||
|
|
@ -24,7 +23,7 @@ def close_db(e=None):
|
|||
"""If this request connected to the database, close the
|
||||
connection.
|
||||
"""
|
||||
db = g.pop('db', None)
|
||||
db = g.pop("db", None)
|
||||
|
||||
if db is not None:
|
||||
db.close()
|
||||
|
|
@ -34,16 +33,16 @@ def init_db():
|
|||
"""Clear existing data and create new tables."""
|
||||
db = get_db()
|
||||
|
||||
with current_app.open_resource('schema.sql') as f:
|
||||
db.executescript(f.read().decode('utf8'))
|
||||
with current_app.open_resource("schema.sql") as f:
|
||||
db.executescript(f.read().decode("utf8"))
|
||||
|
||||
|
||||
@click.command('init-db')
|
||||
@click.command("init-db")
|
||||
@with_appcontext
|
||||
def init_db_command():
|
||||
"""Clear existing data and create new tables."""
|
||||
init_db()
|
||||
click.echo('Initialized the database.')
|
||||
click.echo("Initialized the database.")
|
||||
|
||||
|
||||
def init_app(app):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue