summaryrefslogtreecommitdiffstats
path: root/flaskr
diff options
context:
space:
mode:
Diffstat (limited to 'flaskr')
-rw-r--r--flaskr/__init__.py10
-rw-r--r--flaskr/db.py4
-rw-r--r--flaskr/templates/blog/create.html15
-rw-r--r--flaskr/templates/blog/index.html30
-rw-r--r--flaskr/templates/blog/update.html20
-rw-r--r--flaskr/views/auth.py2
-rw-r--r--flaskr/views/blog.py104
7 files changed, 182 insertions, 3 deletions
diff --git a/flaskr/__init__.py b/flaskr/__init__.py
index 0366365..3f068e8 100644
--- a/flaskr/__init__.py
+++ b/flaskr/__init__.py
@@ -7,7 +7,7 @@ def create_app(test_config=None):
# Create app object. Configuration files are relative to instance folder.
app = Flask(__name__, instance_relative_config=True)
- # config
+ # Config
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'flaskr.sqlite'),
@@ -24,7 +24,7 @@ def create_app(test_config=None):
pass
# Routes
- @app.route('/')
+ @app.route('/hello')
def index():
return 'Hello, World!'
@@ -35,4 +35,10 @@ def create_app(test_config=None):
from .views import auth
app.register_blueprint(auth.bp)
+ from .views import blog
+ app.register_blueprint(blog.bp)
+
+ # Extra
+ app.add_url_rule('/', endpoint='index')
+
return app \ No newline at end of file
diff --git a/flaskr/db.py b/flaskr/db.py
index 7185da8..eb4e8b4 100644
--- a/flaskr/db.py
+++ b/flaskr/db.py
@@ -5,6 +5,10 @@ from flask import current_app, g
def get_db():
+ """Returns database connection
+
+ sqlite3: https://docs.python.org/3/library/sqlite3.html
+ """
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
diff --git a/flaskr/templates/blog/create.html b/flaskr/templates/blog/create.html
new file mode 100644
index 0000000..88e31e4
--- /dev/null
+++ b/flaskr/templates/blog/create.html
@@ -0,0 +1,15 @@
+{% extends 'base.html' %}
+
+{% block header %}
+ <h1>{% block title %}New Post{% endblock %}</h1>
+{% endblock %}
+
+{% block content %}
+ <form method="post">
+ <label for="title">Title</label>
+ <input name="title" id="title" value="{{ request.form['title'] }}" required>
+ <label for="body">Body</label>
+ <textarea name="body" id="body">{{ request.form['body'] }}</textarea>
+ <input type="submit" value="Save">
+ </form>
+{% endblock %}
diff --git a/flaskr/templates/blog/index.html b/flaskr/templates/blog/index.html
new file mode 100644
index 0000000..0d3ed17
--- /dev/null
+++ b/flaskr/templates/blog/index.html
@@ -0,0 +1,30 @@
+{% extends 'base.html' %}
+
+
+{% block header %}
+ <h1>{% block title %}Posts{% endblock %}</h1>
+ {% if g.user %}
+ <a class="action" href="{{ url_for('blog.create') }}">New</a>
+ {% endif %}
+{% endblock %}
+
+{% block content %}
+ {% for post in posts %}
+ <article class="post">
+ <header>
+ <div>
+ <h1>{{ post['title'] }}</h1>
+ <div class="about">by {{ post['username'] }} on {{ post['created'].strftime('%Y-%m-%d') }}</div>
+ </div>
+ {% if g.user['id'] == post['author_id'] %}
+ <a class="action" href="{{ url_for('blog.update', id=post['id']) }}">Edit</a>
+ {% endif %}
+ </header>
+ <p class="body">{{ post['body'] }}</p>
+ </article>
+ {% if not loop.last %}
+ {# Separate posts with a line #}
+ <hr>
+ {% endif %}
+ {% endfor %}
+{% endblock %} \ No newline at end of file
diff --git a/flaskr/templates/blog/update.html b/flaskr/templates/blog/update.html
new file mode 100644
index 0000000..7420f57
--- /dev/null
+++ b/flaskr/templates/blog/update.html
@@ -0,0 +1,20 @@
+{% extends 'base.html' %}
+
+{% block header %}
+ <h1>{% block title %}Edit "{{ post['title'] }}"{% endblock %}</h1>
+{% endblock %}
+
+{% block content %}
+ <form method="post">
+ <label for="title">Title</label>
+ <input name="title" id="title"
+ value="{{ request.form['title'] or post['title'] }}" required>
+ <label for="body">Body</label>
+ <textarea name="body" id="body">{{ request.form['body'] or post['body'] }}</textarea>
+ <input type="submit" value="Save">
+ </form>
+ <hr>
+ <form action="{{ url_for('blog.delete', id=post['id']) }}" method="post">
+ <input class="danger" type="submit" value="Delete" onclick="return confirm('Are you sure?');">
+ </form>
+{% endblock %} \ No newline at end of file
diff --git a/flaskr/views/auth.py b/flaskr/views/auth.py
index 3689eba..2dc32af 100644
--- a/flaskr/views/auth.py
+++ b/flaskr/views/auth.py
@@ -31,7 +31,7 @@ def register():
# (otherwise SQL injection vulnerability)
db.execute(
"INSERT INTO user (username, password) VALUES (?, ?)",
- (username, generate_password_hash(password)),
+ (username, generate_password_hash(password))
)
db.commit()
except db.IntegrityError:
diff --git a/flaskr/views/blog.py b/flaskr/views/blog.py
new file mode 100644
index 0000000..6f728ea
--- /dev/null
+++ b/flaskr/views/blog.py
@@ -0,0 +1,104 @@
+from flask import (
+ Blueprint, flash, g, redirect, render_template, request, url_for
+)
+from werkzeug.exceptions import abort
+
+from flaskr.views.auth import login_required
+from flaskr.db import get_db
+
+# NOTE: no URL prefix
+bp = Blueprint('blog', __name__)
+
+
+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)
+
+
[email protected]('/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')
+
+
[email protected]('/<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)
+
+
[email protected]('/<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'))
+
+
+# Helper functions:
+
+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, f"Post id {id} doesn't exist.")
+
+ if check_author and post['author_id'] != g.user['id']:
+ abort(403)
+
+ return post