Skip to content

Commit

Permalink
FLASKR
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastián Rojas Ortiz authored and Sebastián Rojas Ortiz committed Oct 28, 2020
0 parents commit e4900bd
Show file tree
Hide file tree
Showing 21 changed files with 815 additions and 0 deletions.
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include flaskr/schema.sql
graft flaskr/static
graft flaskr/templates
global-exclude *.pyc
43 changes: 43 additions & 0 deletions flaskr/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import os

from flask import Flask


def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev',
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)
else:
# load the test config if passed in
app.config.from_mapping(test_config)

# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass

# a simple page that says hello
@app.route('/hello')
def hello():
return 'Hello, World!'

from . import db
db.init_app(app)

from . import auth
app.register_blueprint(auth.bp)

from . import blog
app.register_blueprint(blog.bp)
app.add_url_rule('/', endpoint='index')

return app

93 changes: 93 additions & 0 deletions flaskr/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import functools

from flask import (
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.route('/register', methods=('GET', 'POST'))
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
error = None

if not username:
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 {} is already registered.'.format(username)

if error is None:
db.execute(
'INSERT INTO user (username, password) VALUES (?, ?)',
(username, generate_password_hash(password))
)
db.commit()
return redirect(url_for('auth.login'))

flash(error)

return render_template('auth/register.html')

@bp.route('/login', methods=('GET', 'POST'))
def login():
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,)
).fetchone()

if user is None:
error = 'Incorrect username.'
elif not check_password_hash(user['password'], password):
error = 'Incorrect password.'

if error is None:
session.clear()
session['user_id'] = user['id']
return redirect(url_for('index'))

flash(error)

return render_template('auth/login.html')


@bp.before_app_request
def load_logged_in_user():
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()


@bp.route('/logout')
def logout():
session.clear()
return redirect(url_for('index'))


def login_required(view):
@functools.wraps(view)
def wrapped_view(**kwargs):
if g.user is None:
return redirect(url_for('auth.login'))

return view(**kwargs)

return wrapped_view
96 changes: 96 additions & 0 deletions flaskr/blog.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
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.route('/')
def index():
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'
).fetchall()
return render_template('blog/index.html', posts=posts)

@bp.route('/create', methods=('GET', 'POST'))
@login_required
def create():
if request.method == 'POST':
title = request.form['title']
body = request.form['body']
error = None

if not title:
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'])
)
db.commit()
return redirect(url_for('blog.index'))

return render_template('blog/create.html')

def get_post(id, check_author=True):
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']:
abort(403)

return post

@bp.route('/<int:id>/update', methods=('GET', 'POST'))
@login_required
def update(id):
post = get_post(id)

if request.method == 'POST':
title = request.form['title']
body = request.form['body']
error = None

if not title:
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)
)
db.commit()
return redirect(url_for('blog.index'))

return render_template('blog/update.html', post=post)

@bp.route('/<int:id>/delete', methods=('POST',))
@login_required
def delete(id):
get_post(id)
db = get_db()
db.execute('DELETE FROM post WHERE id = ?', (id,))
db.commit()
return redirect(url_for('blog.index'))
43 changes: 43 additions & 0 deletions flaskr/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import sqlite3

import click
from flask import current_app, g
from flask.cli import with_appcontext


def get_db():
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row

return g.db


def close_db(e=None):
db = g.pop('db', None)

if db is not None:
db.close()


def init_db():
db = get_db()

with current_app.open_resource('schema.sql') as f:
db.executescript(f.read().decode('utf8'))


@click.command('init-db')
@with_appcontext
def init_db_command():
"""Clear the existing data and create new tables."""
init_db()
click.echo('Initialized the database.')


def init_app(app):
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)
17 changes: 17 additions & 0 deletions flaskr/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS post;

CREATE TABLE user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL
);

CREATE TABLE post (
id INTEGER PRIMARY KEY AUTOINCREMENT,
author_id INTEGER NOT NULL,
created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
title TEXT NOT NULL,
body TEXT NOT NULL,
FOREIGN KEY (author_id) REFERENCES user (id)
);
Loading

0 comments on commit e4900bd

Please sign in to comment.