From def4d868b6660a863826f18a9e43efbc6f228a2f Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 20 Nov 2023 22:52:40 +0100 Subject: [PATCH 1/5] Add material for the Flask series --- flask-series-part-1/README.md | 84 +++++++++++++++ flask-series-part-1/board/__init__.py | 10 ++ flask-series-part-1/board/pages.py | 13 +++ flask-series-part-1/board/static/styles.css | 34 ++++++ .../board/templates/_navigation.html | 6 ++ flask-series-part-1/board/templates/base.html | 19 ++++ .../board/templates/pages/about.html | 9 ++ .../board/templates/pages/home.html | 9 ++ flask-series-part-1/requirements.txt | 3 + flask-series-part-2/README.md | 84 +++++++++++++++ flask-series-part-2/board/__init__.py | 20 ++++ flask-series-part-2/board/database.py | 36 +++++++ flask-series-part-2/board/pages.py | 13 +++ flask-series-part-2/board/posts.py | 38 +++++++ flask-series-part-2/board/schema.sql | 8 ++ flask-series-part-2/board/static/styles.css | 86 +++++++++++++++ .../board/templates/_navigation.html | 8 ++ flask-series-part-2/board/templates/base.html | 19 ++++ .../board/templates/pages/about.html | 9 ++ .../board/templates/pages/home.html | 9 ++ .../board/templates/posts/create.html | 21 ++++ .../board/templates/posts/posts.html | 14 +++ flask-series-part-2/requirements.txt | 3 + flask-series-part-3/README.md | 84 +++++++++++++++ flask-series-part-3/board/__init__.py | 27 +++++ flask-series-part-3/board/database.py | 36 +++++++ flask-series-part-3/board/errors.py | 6 ++ flask-series-part-3/board/pages.py | 13 +++ flask-series-part-3/board/posts.py | 44 ++++++++ flask-series-part-3/board/schema.sql | 8 ++ flask-series-part-3/board/static/styles.css | 101 ++++++++++++++++++ .../board/templates/_navigation.html | 8 ++ flask-series-part-3/board/templates/base.html | 22 ++++ .../board/templates/errors/404.html | 12 +++ .../board/templates/pages/about.html | 9 ++ .../board/templates/pages/home.html | 9 ++ .../board/templates/posts/create.html | 21 ++++ .../board/templates/posts/posts.html | 14 +++ flask-series-part-3/requirements.txt | 3 + 39 files changed, 972 insertions(+) create mode 100644 flask-series-part-1/README.md create mode 100644 flask-series-part-1/board/__init__.py create mode 100644 flask-series-part-1/board/pages.py create mode 100644 flask-series-part-1/board/static/styles.css create mode 100644 flask-series-part-1/board/templates/_navigation.html create mode 100644 flask-series-part-1/board/templates/base.html create mode 100644 flask-series-part-1/board/templates/pages/about.html create mode 100644 flask-series-part-1/board/templates/pages/home.html create mode 100644 flask-series-part-1/requirements.txt create mode 100644 flask-series-part-2/README.md create mode 100644 flask-series-part-2/board/__init__.py create mode 100644 flask-series-part-2/board/database.py create mode 100644 flask-series-part-2/board/pages.py create mode 100644 flask-series-part-2/board/posts.py create mode 100644 flask-series-part-2/board/schema.sql create mode 100644 flask-series-part-2/board/static/styles.css create mode 100644 flask-series-part-2/board/templates/_navigation.html create mode 100644 flask-series-part-2/board/templates/base.html create mode 100644 flask-series-part-2/board/templates/pages/about.html create mode 100644 flask-series-part-2/board/templates/pages/home.html create mode 100644 flask-series-part-2/board/templates/posts/create.html create mode 100644 flask-series-part-2/board/templates/posts/posts.html create mode 100644 flask-series-part-2/requirements.txt create mode 100644 flask-series-part-3/README.md create mode 100644 flask-series-part-3/board/__init__.py create mode 100644 flask-series-part-3/board/database.py create mode 100644 flask-series-part-3/board/errors.py create mode 100644 flask-series-part-3/board/pages.py create mode 100644 flask-series-part-3/board/posts.py create mode 100644 flask-series-part-3/board/schema.sql create mode 100644 flask-series-part-3/board/static/styles.css create mode 100644 flask-series-part-3/board/templates/_navigation.html create mode 100644 flask-series-part-3/board/templates/base.html create mode 100644 flask-series-part-3/board/templates/errors/404.html create mode 100644 flask-series-part-3/board/templates/pages/about.html create mode 100644 flask-series-part-3/board/templates/pages/home.html create mode 100644 flask-series-part-3/board/templates/posts/create.html create mode 100644 flask-series-part-3/board/templates/posts/posts.html create mode 100644 flask-series-part-3/requirements.txt diff --git a/flask-series-part-1/README.md b/flask-series-part-1/README.md new file mode 100644 index 0000000000..0a6beec081 --- /dev/null +++ b/flask-series-part-1/README.md @@ -0,0 +1,84 @@ +# Flask Series: Sample Project + +This repository contains the code for the `board` Flask sample project. + +## Setup + +You can run the provided example project on your local machine by following the steps outlined below. + +Create a new virtual environment: + +```bash +python3 -m venv venv/ +``` + +Activate the virtual environment: + +```bash +source ./venv/bin/activate +``` + +Navigate to the folder for the step that you're currently on. + +Install the dependencies for this project if you haven't installed them yet: + +```bash +(venv) $ python -m pip install -r requirements.txt +``` + +### Environment Variables + +This project works with environment variables that the application expects in a `.env` file inside the root directory of your project. + +Create a `.env` file with this content: + +``` +FLASK_SECRET_KEY="mysecretkey" +FLASK_DATABASE="board.sqlite" +``` + +You can add your own content there, but you must define it before running the Flask application. + +#### Secret Key + +If you want to deploy your Flask app later, then it's a good idea to generate a proper secret key. + +If you need to create cryptographically sound data like a Flask secret key, then you can use Python's [`secrets`](https://docs.python.org/3/library/secrets.html) module: + +```pycon +>>> import secrets +>>> secrets.token_hex() +'2e9ac41b1e0b66a8d93d66400e2300c4b4c2953f' +``` + +The `.token_hex()` method returns a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) string containing random numbers and letters from `0` to `9` and `a` to `f`. Use the value that `secrets.token_hex()` outputs for you and add it to your Flask project's `.env` file: + +``` +# .env + +FLASK_SECRET_KEY="2e9ac41b1e0b66a8d93d66400e2300c4b4c2953f" +FLASK_DATABASE="board.sqlite" + +``` + +To avoid saving the secret key directly in your code, it may be a good idea to work with [environment variables](https://12factor.net/config). You can learn more about that in the Flask documentation on [configuration handling](https://flask.palletsprojects.com/en/2.3.x/config/). + +### Database + +To initialize the database, run this command: + +```bash +(venv) $ python -m flask --app board init-db +``` + +If you used the content for the `.env` file from above, then you can find a `board.sqlite` database in the root directory of your project. + +## Development Server + +To run the Flask development server, enter this command in your terminal while being in the root directory of your project: + +```bash +(venv) $ python -m flask --app board run --debug +``` + +Now you can navigate to the address that's shown in the output when you start the server. Commonly, that's `http://localhost:5000/`. diff --git a/flask-series-part-1/board/__init__.py b/flask-series-part-1/board/__init__.py new file mode 100644 index 0000000000..f58a5cf330 --- /dev/null +++ b/flask-series-part-1/board/__init__.py @@ -0,0 +1,10 @@ +from flask import Flask + +from board import pages + + +def create_app(): + app = Flask(__name__) + + app.register_blueprint(pages.bp) + return app diff --git a/flask-series-part-1/board/pages.py b/flask-series-part-1/board/pages.py new file mode 100644 index 0000000000..54c8306fa5 --- /dev/null +++ b/flask-series-part-1/board/pages.py @@ -0,0 +1,13 @@ +from flask import Blueprint, render_template + +bp = Blueprint("pages", __name__) + + +@bp.route("/") +def home(): + return render_template("pages/home.html") + + +@bp.route("/about") +def about(): + return render_template("pages/about.html") diff --git a/flask-series-part-1/board/static/styles.css b/flask-series-part-1/board/static/styles.css new file mode 100644 index 0000000000..bd2341b45a --- /dev/null +++ b/flask-series-part-1/board/static/styles.css @@ -0,0 +1,34 @@ +* { + box-sizing: border-box; +} + +body { + font-family: sans-serif; + font-size: 20px; + margin: 0 auto; + text-align: center; +} + +a, +a:visited { + color: #007BFF; +} + +a:hover { + color: #0056b3; +} + +nav ul { + list-style-type: none; + padding: 0; +} + +nav ul li { + display: inline; + margin: 0 5px; +} + +main { + width: 80%; + margin: 0 auto; +} diff --git a/flask-series-part-1/board/templates/_navigation.html b/flask-series-part-1/board/templates/_navigation.html new file mode 100644 index 0000000000..50c1304d4e --- /dev/null +++ b/flask-series-part-1/board/templates/_navigation.html @@ -0,0 +1,6 @@ + diff --git a/flask-series-part-1/board/templates/base.html b/flask-series-part-1/board/templates/base.html new file mode 100644 index 0000000000..e948d8ac29 --- /dev/null +++ b/flask-series-part-1/board/templates/base.html @@ -0,0 +1,19 @@ + + + + Message Board - {% block title %}{% endblock title %} + + + +

Message Board

+{% include("_navigation.html") %} +
+
+ {% block header %}{% endblock header %} +
+
+ {% block content %}

No messages.

{% endblock content %} +
+
+ + diff --git a/flask-series-part-1/board/templates/pages/about.html b/flask-series-part-1/board/templates/pages/about.html new file mode 100644 index 0000000000..d51dae459c --- /dev/null +++ b/flask-series-part-1/board/templates/pages/about.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}About{% endblock %}

+{% endblock header %} + +{% block content %} +

This is a message board for friendly messages.

+{% endblock content %} diff --git a/flask-series-part-1/board/templates/pages/home.html b/flask-series-part-1/board/templates/pages/home.html new file mode 100644 index 0000000000..6963fcc11d --- /dev/null +++ b/flask-series-part-1/board/templates/pages/home.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Home{% endblock %}

+{% endblock header %} + +{% block content %} +

Learn more about this project by visiting the About page.

+{% endblock content %} diff --git a/flask-series-part-1/requirements.txt b/flask-series-part-1/requirements.txt new file mode 100644 index 0000000000..6c7cdaeb4b --- /dev/null +++ b/flask-series-part-1/requirements.txt @@ -0,0 +1,3 @@ +click==8.1.7 +Flask==3.0.0 +python-dotenv==1.0.0 diff --git a/flask-series-part-2/README.md b/flask-series-part-2/README.md new file mode 100644 index 0000000000..0a6beec081 --- /dev/null +++ b/flask-series-part-2/README.md @@ -0,0 +1,84 @@ +# Flask Series: Sample Project + +This repository contains the code for the `board` Flask sample project. + +## Setup + +You can run the provided example project on your local machine by following the steps outlined below. + +Create a new virtual environment: + +```bash +python3 -m venv venv/ +``` + +Activate the virtual environment: + +```bash +source ./venv/bin/activate +``` + +Navigate to the folder for the step that you're currently on. + +Install the dependencies for this project if you haven't installed them yet: + +```bash +(venv) $ python -m pip install -r requirements.txt +``` + +### Environment Variables + +This project works with environment variables that the application expects in a `.env` file inside the root directory of your project. + +Create a `.env` file with this content: + +``` +FLASK_SECRET_KEY="mysecretkey" +FLASK_DATABASE="board.sqlite" +``` + +You can add your own content there, but you must define it before running the Flask application. + +#### Secret Key + +If you want to deploy your Flask app later, then it's a good idea to generate a proper secret key. + +If you need to create cryptographically sound data like a Flask secret key, then you can use Python's [`secrets`](https://docs.python.org/3/library/secrets.html) module: + +```pycon +>>> import secrets +>>> secrets.token_hex() +'2e9ac41b1e0b66a8d93d66400e2300c4b4c2953f' +``` + +The `.token_hex()` method returns a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) string containing random numbers and letters from `0` to `9` and `a` to `f`. Use the value that `secrets.token_hex()` outputs for you and add it to your Flask project's `.env` file: + +``` +# .env + +FLASK_SECRET_KEY="2e9ac41b1e0b66a8d93d66400e2300c4b4c2953f" +FLASK_DATABASE="board.sqlite" + +``` + +To avoid saving the secret key directly in your code, it may be a good idea to work with [environment variables](https://12factor.net/config). You can learn more about that in the Flask documentation on [configuration handling](https://flask.palletsprojects.com/en/2.3.x/config/). + +### Database + +To initialize the database, run this command: + +```bash +(venv) $ python -m flask --app board init-db +``` + +If you used the content for the `.env` file from above, then you can find a `board.sqlite` database in the root directory of your project. + +## Development Server + +To run the Flask development server, enter this command in your terminal while being in the root directory of your project: + +```bash +(venv) $ python -m flask --app board run --debug +``` + +Now you can navigate to the address that's shown in the output when you start the server. Commonly, that's `http://localhost:5000/`. diff --git a/flask-series-part-2/board/__init__.py b/flask-series-part-2/board/__init__.py new file mode 100644 index 0000000000..eedb72d5bf --- /dev/null +++ b/flask-series-part-2/board/__init__.py @@ -0,0 +1,20 @@ +import os +from dotenv import load_dotenv +from flask import Flask + +from board import pages, database, posts + +load_dotenv() + + +def create_app(): + app = Flask(__name__) + app.config.from_prefixed_env() + + database.init_app(app) + + app.register_blueprint(pages.bp) + app.register_blueprint(posts.bp) + print(f"Current Environment: {os.getenv('ENVIRONMENT')}") + print(f"Using Database: {app.config.get('DATABASE')}") + return app diff --git a/flask-series-part-2/board/database.py b/flask-series-part-2/board/database.py new file mode 100644 index 0000000000..319f36da9b --- /dev/null +++ b/flask-series-part-2/board/database.py @@ -0,0 +1,36 @@ +import sqlite3 +import click +from flask import current_app, g + + +def init_app(app): + app.teardown_appcontext(close_db) + app.cli.add_command(init_db_command) + + +@click.command("init-db") +def init_db_command(): + db = get_db() + + with current_app.open_resource("schema.sql") as f: + db.executescript(f.read().decode("utf8")) + + click.echo("You successfully initialized the database!") + + +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() diff --git a/flask-series-part-2/board/pages.py b/flask-series-part-2/board/pages.py new file mode 100644 index 0000000000..54c8306fa5 --- /dev/null +++ b/flask-series-part-2/board/pages.py @@ -0,0 +1,13 @@ +from flask import Blueprint, render_template + +bp = Blueprint("pages", __name__) + + +@bp.route("/") +def home(): + return render_template("pages/home.html") + + +@bp.route("/about") +def about(): + return render_template("pages/about.html") diff --git a/flask-series-part-2/board/posts.py b/flask-series-part-2/board/posts.py new file mode 100644 index 0000000000..e090cefac7 --- /dev/null +++ b/flask-series-part-2/board/posts.py @@ -0,0 +1,38 @@ +from flask import ( + Blueprint, + redirect, + render_template, + request, + url_for, +) + +from board.database import get_db + +bp = Blueprint("posts", __name__) + + +@bp.route("/create", methods=("GET", "POST")) +def create(): + if request.method == "POST": + author = request.form["author"] or "Anonymous" + message = request.form["message"] + + if message: + db = get_db() + db.execute( + "INSERT INTO post (author, message) VALUES (?, ?)", + (author, message), + ) + db.commit() + return redirect(url_for("posts.posts")) + + return render_template("posts/create.html") + + +@bp.route("/posts") +def posts(): + db = get_db() + posts = db.execute( + "SELECT author, message, created FROM post ORDER BY created DESC" + ).fetchall() + return render_template("posts/posts.html", posts=posts) diff --git a/flask-series-part-2/board/schema.sql b/flask-series-part-2/board/schema.sql new file mode 100644 index 0000000000..52bf2c3504 --- /dev/null +++ b/flask-series-part-2/board/schema.sql @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS post; + +CREATE TABLE post ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + author TEXT NOT NULL, + message TEXT NOT NULL +); diff --git a/flask-series-part-2/board/static/styles.css b/flask-series-part-2/board/static/styles.css new file mode 100644 index 0000000000..b62b7130d0 --- /dev/null +++ b/flask-series-part-2/board/static/styles.css @@ -0,0 +1,86 @@ +* { + box-sizing: border-box; +} + +body { + font-family: sans-serif; + font-size: 20px; + margin: 0 auto; + text-align: center; +} + +a, +a:visited { + color: #007BFF; +} + +a:hover { + color: #0056b3; +} + +nav ul { + list-style-type: none; + padding: 0; +} + +nav ul li { + display: inline; + margin: 0 5px; +} + +main { + width: 80%; + margin: 0 auto; +} + +article, form { + text-align: left; + min-width: 200px; + padding: 20px; + margin-bottom: 20px; + box-shadow: 0px 0px 10px #ccc; + vertical-align: top; +} + +aside { + color: #ccc; + text-align: right; +} + +form { + display: flex; + flex-direction: column; + margin-top: 20px; +} + +.form-group { + margin-bottom: 20px; +} + +.form-control { + width: 100%; + padding: 10px; + border: 1px solid #ccc; + font-size: 1em; +} + +.submit-btn { + background-color: #007BFF; + color: #fff; + border: none; + border-radius: 4px; + padding: 10px 20px; + cursor: pointer; + font-size: 1em; +} + +.submit-btn:hover { + background-color: #0056b3; +} + +.message { + font-size: 2.5em; + font-family: serif; + margin: 0; + padding: 0; +} diff --git a/flask-series-part-2/board/templates/_navigation.html b/flask-series-part-2/board/templates/_navigation.html new file mode 100644 index 0000000000..609bff1ecc --- /dev/null +++ b/flask-series-part-2/board/templates/_navigation.html @@ -0,0 +1,8 @@ + diff --git a/flask-series-part-2/board/templates/base.html b/flask-series-part-2/board/templates/base.html new file mode 100644 index 0000000000..e948d8ac29 --- /dev/null +++ b/flask-series-part-2/board/templates/base.html @@ -0,0 +1,19 @@ + + + + Message Board - {% block title %}{% endblock title %} + + + +

Message Board

+{% include("_navigation.html") %} +
+
+ {% block header %}{% endblock header %} +
+
+ {% block content %}

No messages.

{% endblock content %} +
+
+ + diff --git a/flask-series-part-2/board/templates/pages/about.html b/flask-series-part-2/board/templates/pages/about.html new file mode 100644 index 0000000000..d51dae459c --- /dev/null +++ b/flask-series-part-2/board/templates/pages/about.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}About{% endblock %}

+{% endblock header %} + +{% block content %} +

This is a message board for friendly messages.

+{% endblock content %} diff --git a/flask-series-part-2/board/templates/pages/home.html b/flask-series-part-2/board/templates/pages/home.html new file mode 100644 index 0000000000..6963fcc11d --- /dev/null +++ b/flask-series-part-2/board/templates/pages/home.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Home{% endblock %}

+{% endblock header %} + +{% block content %} +

Learn more about this project by visiting the About page.

+{% endblock content %} diff --git a/flask-series-part-2/board/templates/posts/create.html b/flask-series-part-2/board/templates/posts/create.html new file mode 100644 index 0000000000..deb2542035 --- /dev/null +++ b/flask-series-part-2/board/templates/posts/create.html @@ -0,0 +1,21 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Add Post{% endblock %}

+{% endblock %} + +{% block content %} +
+
+ + +
+
+ + +
+
+ +
+
+{% endblock %} diff --git a/flask-series-part-2/board/templates/posts/posts.html b/flask-series-part-2/board/templates/posts/posts.html new file mode 100644 index 0000000000..cd73793995 --- /dev/null +++ b/flask-series-part-2/board/templates/posts/posts.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Posts{% endblock %}

+{% endblock %} + +{% block content %} + {% for post in posts %} +
+

{{ post["message"] }}

+

+
+ {% endfor %} +{% endblock %} diff --git a/flask-series-part-2/requirements.txt b/flask-series-part-2/requirements.txt new file mode 100644 index 0000000000..6c7cdaeb4b --- /dev/null +++ b/flask-series-part-2/requirements.txt @@ -0,0 +1,3 @@ +click==8.1.7 +Flask==3.0.0 +python-dotenv==1.0.0 diff --git a/flask-series-part-3/README.md b/flask-series-part-3/README.md new file mode 100644 index 0000000000..0a6beec081 --- /dev/null +++ b/flask-series-part-3/README.md @@ -0,0 +1,84 @@ +# Flask Series: Sample Project + +This repository contains the code for the `board` Flask sample project. + +## Setup + +You can run the provided example project on your local machine by following the steps outlined below. + +Create a new virtual environment: + +```bash +python3 -m venv venv/ +``` + +Activate the virtual environment: + +```bash +source ./venv/bin/activate +``` + +Navigate to the folder for the step that you're currently on. + +Install the dependencies for this project if you haven't installed them yet: + +```bash +(venv) $ python -m pip install -r requirements.txt +``` + +### Environment Variables + +This project works with environment variables that the application expects in a `.env` file inside the root directory of your project. + +Create a `.env` file with this content: + +``` +FLASK_SECRET_KEY="mysecretkey" +FLASK_DATABASE="board.sqlite" +``` + +You can add your own content there, but you must define it before running the Flask application. + +#### Secret Key + +If you want to deploy your Flask app later, then it's a good idea to generate a proper secret key. + +If you need to create cryptographically sound data like a Flask secret key, then you can use Python's [`secrets`](https://docs.python.org/3/library/secrets.html) module: + +```pycon +>>> import secrets +>>> secrets.token_hex() +'2e9ac41b1e0b66a8d93d66400e2300c4b4c2953f' +``` + +The `.token_hex()` method returns a [hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal) string containing random numbers and letters from `0` to `9` and `a` to `f`. Use the value that `secrets.token_hex()` outputs for you and add it to your Flask project's `.env` file: + +``` +# .env + +FLASK_SECRET_KEY="2e9ac41b1e0b66a8d93d66400e2300c4b4c2953f" +FLASK_DATABASE="board.sqlite" + +``` + +To avoid saving the secret key directly in your code, it may be a good idea to work with [environment variables](https://12factor.net/config). You can learn more about that in the Flask documentation on [configuration handling](https://flask.palletsprojects.com/en/2.3.x/config/). + +### Database + +To initialize the database, run this command: + +```bash +(venv) $ python -m flask --app board init-db +``` + +If you used the content for the `.env` file from above, then you can find a `board.sqlite` database in the root directory of your project. + +## Development Server + +To run the Flask development server, enter this command in your terminal while being in the root directory of your project: + +```bash +(venv) $ python -m flask --app board run --debug +``` + +Now you can navigate to the address that's shown in the output when you start the server. Commonly, that's `http://localhost:5000/`. diff --git a/flask-series-part-3/board/__init__.py b/flask-series-part-3/board/__init__.py new file mode 100644 index 0000000000..1c4d7ef534 --- /dev/null +++ b/flask-series-part-3/board/__init__.py @@ -0,0 +1,27 @@ +import os +from dotenv import load_dotenv +from flask import Flask + +from board import ( + database, + errors, + pages, + posts, +) + +load_dotenv() + + +def create_app(): + app = Flask(__name__) + app.config.from_prefixed_env() + # app.logger.setLevel("INFO") + + database.init_app(app) + + app.register_blueprint(pages.bp) + app.register_blueprint(posts.bp) + app.register_error_handler(404, errors.page_not_found) + app.logger.debug(f"Current Environment: {os.getenv('ENVIRONMENT')}") + app.logger.debug(f"Using Database: {app.config.get('DATABASE')}") + return app diff --git a/flask-series-part-3/board/database.py b/flask-series-part-3/board/database.py new file mode 100644 index 0000000000..319f36da9b --- /dev/null +++ b/flask-series-part-3/board/database.py @@ -0,0 +1,36 @@ +import sqlite3 +import click +from flask import current_app, g + + +def init_app(app): + app.teardown_appcontext(close_db) + app.cli.add_command(init_db_command) + + +@click.command("init-db") +def init_db_command(): + db = get_db() + + with current_app.open_resource("schema.sql") as f: + db.executescript(f.read().decode("utf8")) + + click.echo("You successfully initialized the database!") + + +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() diff --git a/flask-series-part-3/board/errors.py b/flask-series-part-3/board/errors.py new file mode 100644 index 0000000000..8bfbebfd1a --- /dev/null +++ b/flask-series-part-3/board/errors.py @@ -0,0 +1,6 @@ +from flask import current_app, render_template, request + + +def page_not_found(e): + current_app.logger.info(f"'{e.name}' error ({e.code}) at {request.url}") + return render_template("errors/404.html"), 404 diff --git a/flask-series-part-3/board/pages.py b/flask-series-part-3/board/pages.py new file mode 100644 index 0000000000..54c8306fa5 --- /dev/null +++ b/flask-series-part-3/board/pages.py @@ -0,0 +1,13 @@ +from flask import Blueprint, render_template + +bp = Blueprint("pages", __name__) + + +@bp.route("/") +def home(): + return render_template("pages/home.html") + + +@bp.route("/about") +def about(): + return render_template("pages/about.html") diff --git a/flask-series-part-3/board/posts.py b/flask-series-part-3/board/posts.py new file mode 100644 index 0000000000..40c0c756c3 --- /dev/null +++ b/flask-series-part-3/board/posts.py @@ -0,0 +1,44 @@ +from flask import ( + Blueprint, + current_app, + flash, + redirect, + render_template, + request, + url_for, +) + +from board.database import get_db + +bp = Blueprint("posts", __name__) + + +@bp.route("/create", methods=("GET", "POST")) +def create(): + if request.method == "POST": + author = request.form["author"] or "Anonymous" + message = request.form["message"] + + if message: + db = get_db() + db.execute( + "INSERT INTO post (author, message) VALUES (?, ?)", + (author, message), + ) + db.commit() + current_app.logger.info(f"New post by {author}") + flash(f"Thanks for posting, {author}!", category="success") + return redirect(url_for("posts.posts")) + else: + flash("You need to post a message.", category="error") + + return render_template("posts/create.html") + + +@bp.route("/posts") +def posts(): + db = get_db() + posts = db.execute( + "SELECT author, message, created FROM post ORDER BY created DESC" + ).fetchall() + return render_template("posts/posts.html", posts=posts) diff --git a/flask-series-part-3/board/schema.sql b/flask-series-part-3/board/schema.sql new file mode 100644 index 0000000000..52bf2c3504 --- /dev/null +++ b/flask-series-part-3/board/schema.sql @@ -0,0 +1,8 @@ +DROP TABLE IF EXISTS post; + +CREATE TABLE post ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + author TEXT NOT NULL, + message TEXT NOT NULL +); diff --git a/flask-series-part-3/board/static/styles.css b/flask-series-part-3/board/static/styles.css new file mode 100644 index 0000000000..e6ffbe36e8 --- /dev/null +++ b/flask-series-part-3/board/static/styles.css @@ -0,0 +1,101 @@ +* { + box-sizing: border-box; +} + +body { + font-family: sans-serif; + font-size: 20px; + margin: 0 auto; + text-align: center; +} + +a, +a:visited { + color: #007BFF; +} + +a:hover { + color: #0056b3; +} + +nav ul { + list-style-type: none; + padding: 0; +} + +nav ul li { + display: inline; + margin: 0 5px; +} + +main { + width: 80%; + margin: 0 auto; +} + +article, form { + text-align: left; + min-width: 200px; + padding: 20px; + margin-bottom: 20px; + box-shadow: 0px 0px 10px #ccc; + vertical-align: top; +} + +aside { + color: #ccc; + text-align: right; +} + +form { + display: flex; + flex-direction: column; + margin-top: 20px; +} + +.form-group { + margin-bottom: 20px; +} + +.form-control { + width: 100%; + padding: 10px; + border: 1px solid #ccc; + font-size: 1em; +} + +.submit-btn { + background-color: #007BFF; + color: #fff; + border: none; + border-radius: 4px; + padding: 10px 20px; + cursor: pointer; + font-size: 1em; +} + +.submit-btn:hover { + background-color: #0056b3; +} + +.message { + font-size: 2.5em; + font-family: serif; + margin: 0; + padding: 0; +} + +.flash { + padding: 20px; + margin: 20px; +} + +.flash.error { + background-color: #ffa7ae; + color: #a02a36; +} + +.flash.success { + background-color: #96faad; + color: #1c7530; +} diff --git a/flask-series-part-3/board/templates/_navigation.html b/flask-series-part-3/board/templates/_navigation.html new file mode 100644 index 0000000000..609bff1ecc --- /dev/null +++ b/flask-series-part-3/board/templates/_navigation.html @@ -0,0 +1,8 @@ + diff --git a/flask-series-part-3/board/templates/base.html b/flask-series-part-3/board/templates/base.html new file mode 100644 index 0000000000..ba11e89ce7 --- /dev/null +++ b/flask-series-part-3/board/templates/base.html @@ -0,0 +1,22 @@ + + + + Message Board - {% block title %}{% endblock title %} + + + +

Message Board

+{% include("_navigation.html") %} +
+
+ {% block header %}{% endblock header %} + {% for category, message in get_flashed_messages(with_categories=true) %} +
{{ message }}
+ {% endfor %} +
+
+ {% block content %}

No messages.

{% endblock content %} +
+
+ + diff --git a/flask-series-part-3/board/templates/errors/404.html b/flask-series-part-3/board/templates/errors/404.html new file mode 100644 index 0000000000..806c291281 --- /dev/null +++ b/flask-series-part-3/board/templates/errors/404.html @@ -0,0 +1,12 @@ + + + + {% block title %}{% endblock %} + + + +

Page not found

+

Please go to one of the pages below:

+ {% include("_navigation.html") %} + + diff --git a/flask-series-part-3/board/templates/pages/about.html b/flask-series-part-3/board/templates/pages/about.html new file mode 100644 index 0000000000..d51dae459c --- /dev/null +++ b/flask-series-part-3/board/templates/pages/about.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}About{% endblock %}

+{% endblock header %} + +{% block content %} +

This is a message board for friendly messages.

+{% endblock content %} diff --git a/flask-series-part-3/board/templates/pages/home.html b/flask-series-part-3/board/templates/pages/home.html new file mode 100644 index 0000000000..6963fcc11d --- /dev/null +++ b/flask-series-part-3/board/templates/pages/home.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Home{% endblock %}

+{% endblock header %} + +{% block content %} +

Learn more about this project by visiting the About page.

+{% endblock content %} diff --git a/flask-series-part-3/board/templates/posts/create.html b/flask-series-part-3/board/templates/posts/create.html new file mode 100644 index 0000000000..deb2542035 --- /dev/null +++ b/flask-series-part-3/board/templates/posts/create.html @@ -0,0 +1,21 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Add Post{% endblock %}

+{% endblock %} + +{% block content %} +
+
+ + +
+
+ + +
+
+ +
+
+{% endblock %} diff --git a/flask-series-part-3/board/templates/posts/posts.html b/flask-series-part-3/board/templates/posts/posts.html new file mode 100644 index 0000000000..cd73793995 --- /dev/null +++ b/flask-series-part-3/board/templates/posts/posts.html @@ -0,0 +1,14 @@ +{% extends 'base.html' %} + +{% block header %} +

{% block title %}Posts{% endblock %}

+{% endblock %} + +{% block content %} + {% for post in posts %} +
+

{{ post["message"] }}

+

+
+ {% endfor %} +{% endblock %} diff --git a/flask-series-part-3/requirements.txt b/flask-series-part-3/requirements.txt new file mode 100644 index 0000000000..6c7cdaeb4b --- /dev/null +++ b/flask-series-part-3/requirements.txt @@ -0,0 +1,3 @@ +click==8.1.7 +Flask==3.0.0 +python-dotenv==1.0.0 From 985a6a920ed04df116b66396fb04f79ad97ad9c9 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 28 Nov 2023 16:02:32 +0100 Subject: [PATCH 2/5] Add block name to endblock tags --- flask-series-part-1/board/templates/pages/about.html | 2 +- flask-series-part-1/board/templates/pages/home.html | 2 +- flask-series-part-2/board/templates/pages/about.html | 2 +- flask-series-part-2/board/templates/pages/home.html | 2 +- flask-series-part-2/board/templates/posts/create.html | 6 +++--- flask-series-part-2/board/templates/posts/posts.html | 6 +++--- flask-series-part-3/board/templates/errors/404.html | 2 +- flask-series-part-3/board/templates/pages/about.html | 2 +- flask-series-part-3/board/templates/pages/home.html | 2 +- flask-series-part-3/board/templates/posts/create.html | 6 +++--- flask-series-part-3/board/templates/posts/posts.html | 6 +++--- 11 files changed, 19 insertions(+), 19 deletions(-) diff --git a/flask-series-part-1/board/templates/pages/about.html b/flask-series-part-1/board/templates/pages/about.html index d51dae459c..d34c3ca2d3 100644 --- a/flask-series-part-1/board/templates/pages/about.html +++ b/flask-series-part-1/board/templates/pages/about.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}About{% endblock %}

+

{% block title %}About{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-1/board/templates/pages/home.html b/flask-series-part-1/board/templates/pages/home.html index 6963fcc11d..8a383cc189 100644 --- a/flask-series-part-1/board/templates/pages/home.html +++ b/flask-series-part-1/board/templates/pages/home.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Home{% endblock %}

+

{% block title %}Home{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-2/board/templates/pages/about.html b/flask-series-part-2/board/templates/pages/about.html index d51dae459c..d34c3ca2d3 100644 --- a/flask-series-part-2/board/templates/pages/about.html +++ b/flask-series-part-2/board/templates/pages/about.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}About{% endblock %}

+

{% block title %}About{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-2/board/templates/pages/home.html b/flask-series-part-2/board/templates/pages/home.html index 6963fcc11d..8a383cc189 100644 --- a/flask-series-part-2/board/templates/pages/home.html +++ b/flask-series-part-2/board/templates/pages/home.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Home{% endblock %}

+

{% block title %}Home{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-2/board/templates/posts/create.html b/flask-series-part-2/board/templates/posts/create.html index deb2542035..0933767689 100644 --- a/flask-series-part-2/board/templates/posts/create.html +++ b/flask-series-part-2/board/templates/posts/create.html @@ -1,8 +1,8 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Add Post{% endblock %}

-{% endblock %} +

{% block title %}Add Post{% endblock title %}

+{% endblock header %} {% block content %}
@@ -18,4 +18,4 @@

{% block title %}Add Post{% endblock %}

-{% endblock %} +{% endblock content %} diff --git a/flask-series-part-2/board/templates/posts/posts.html b/flask-series-part-2/board/templates/posts/posts.html index cd73793995..5b1d94185e 100644 --- a/flask-series-part-2/board/templates/posts/posts.html +++ b/flask-series-part-2/board/templates/posts/posts.html @@ -1,8 +1,8 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Posts{% endblock %}

-{% endblock %} +

{% block title %}Posts{% endblock title %}

+{% endblock header %} {% block content %} {% for post in posts %} @@ -11,4 +11,4 @@

{% block title %}Posts{% endblock %}

{% endfor %} -{% endblock %} +{% endblock content %} diff --git a/flask-series-part-3/board/templates/errors/404.html b/flask-series-part-3/board/templates/errors/404.html index 806c291281..1da818d176 100644 --- a/flask-series-part-3/board/templates/errors/404.html +++ b/flask-series-part-3/board/templates/errors/404.html @@ -1,7 +1,7 @@ - {% block title %}{% endblock %} + {% block title %}{% endblock title %} diff --git a/flask-series-part-3/board/templates/pages/about.html b/flask-series-part-3/board/templates/pages/about.html index d51dae459c..d34c3ca2d3 100644 --- a/flask-series-part-3/board/templates/pages/about.html +++ b/flask-series-part-3/board/templates/pages/about.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}About{% endblock %}

+

{% block title %}About{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-3/board/templates/pages/home.html b/flask-series-part-3/board/templates/pages/home.html index 6963fcc11d..8a383cc189 100644 --- a/flask-series-part-3/board/templates/pages/home.html +++ b/flask-series-part-3/board/templates/pages/home.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Home{% endblock %}

+

{% block title %}Home{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-3/board/templates/posts/create.html b/flask-series-part-3/board/templates/posts/create.html index deb2542035..0933767689 100644 --- a/flask-series-part-3/board/templates/posts/create.html +++ b/flask-series-part-3/board/templates/posts/create.html @@ -1,8 +1,8 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Add Post{% endblock %}

-{% endblock %} +

{% block title %}Add Post{% endblock title %}

+{% endblock header %} {% block content %}
@@ -18,4 +18,4 @@

{% block title %}Add Post{% endblock %}

-{% endblock %} +{% endblock content %} diff --git a/flask-series-part-3/board/templates/posts/posts.html b/flask-series-part-3/board/templates/posts/posts.html index cd73793995..5b1d94185e 100644 --- a/flask-series-part-3/board/templates/posts/posts.html +++ b/flask-series-part-3/board/templates/posts/posts.html @@ -1,8 +1,8 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Posts{% endblock %}

-{% endblock %} +

{% block title %}Posts{% endblock title %}

+{% endblock header %} {% block content %} {% for post in posts %} @@ -11,4 +11,4 @@

{% block title %}Posts{% endblock %}

{% endfor %} -{% endblock %} +{% endblock content %} From 7313395d93f6b6eb769784c76f1dab41c26e6206 Mon Sep 17 00:00:00 2001 From: Philipp Date: Tue, 28 Nov 2023 16:04:01 +0100 Subject: [PATCH 3/5] Fix headline levels --- flask-series-part-1/board/templates/pages/about.html | 2 +- flask-series-part-2/board/templates/pages/about.html | 2 +- flask-series-part-2/board/templates/posts/create.html | 2 +- flask-series-part-2/board/templates/posts/posts.html | 2 +- flask-series-part-3/board/templates/pages/about.html | 2 +- flask-series-part-3/board/templates/posts/create.html | 2 +- flask-series-part-3/board/templates/posts/posts.html | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flask-series-part-1/board/templates/pages/about.html b/flask-series-part-1/board/templates/pages/about.html index d34c3ca2d3..66196a1080 100644 --- a/flask-series-part-1/board/templates/pages/about.html +++ b/flask-series-part-1/board/templates/pages/about.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}About{% endblock title %}

+

{% block title %}About{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-2/board/templates/pages/about.html b/flask-series-part-2/board/templates/pages/about.html index d34c3ca2d3..66196a1080 100644 --- a/flask-series-part-2/board/templates/pages/about.html +++ b/flask-series-part-2/board/templates/pages/about.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}About{% endblock title %}

+

{% block title %}About{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-2/board/templates/posts/create.html b/flask-series-part-2/board/templates/posts/create.html index 0933767689..70c56a2601 100644 --- a/flask-series-part-2/board/templates/posts/create.html +++ b/flask-series-part-2/board/templates/posts/create.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Add Post{% endblock title %}

+

{% block title %}Add Post{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-2/board/templates/posts/posts.html b/flask-series-part-2/board/templates/posts/posts.html index 5b1d94185e..94af3a9f72 100644 --- a/flask-series-part-2/board/templates/posts/posts.html +++ b/flask-series-part-2/board/templates/posts/posts.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Posts{% endblock title %}

+

{% block title %}Posts{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-3/board/templates/pages/about.html b/flask-series-part-3/board/templates/pages/about.html index d34c3ca2d3..66196a1080 100644 --- a/flask-series-part-3/board/templates/pages/about.html +++ b/flask-series-part-3/board/templates/pages/about.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}About{% endblock title %}

+

{% block title %}About{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-3/board/templates/posts/create.html b/flask-series-part-3/board/templates/posts/create.html index 0933767689..70c56a2601 100644 --- a/flask-series-part-3/board/templates/posts/create.html +++ b/flask-series-part-3/board/templates/posts/create.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Add Post{% endblock title %}

+

{% block title %}Add Post{% endblock title %}

{% endblock header %} {% block content %} diff --git a/flask-series-part-3/board/templates/posts/posts.html b/flask-series-part-3/board/templates/posts/posts.html index 5b1d94185e..94af3a9f72 100644 --- a/flask-series-part-3/board/templates/posts/posts.html +++ b/flask-series-part-3/board/templates/posts/posts.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% block header %} -

{% block title %}Posts{% endblock title %}

+

{% block title %}Posts{% endblock title %}

{% endblock header %} {% block content %} From ae4bfe40567c6df234b5343da5a4eb922a511a76 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sat, 9 Dec 2023 10:48:00 +0100 Subject: [PATCH 4/5] Remove database section from readme of part 1 --- flask-series-part-1/README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/flask-series-part-1/README.md b/flask-series-part-1/README.md index 0a6beec081..2289783efd 100644 --- a/flask-series-part-1/README.md +++ b/flask-series-part-1/README.md @@ -63,16 +63,6 @@ FLASK_DATABASE="board.sqlite" To avoid saving the secret key directly in your code, it may be a good idea to work with [environment variables](https://12factor.net/config). You can learn more about that in the Flask documentation on [configuration handling](https://flask.palletsprojects.com/en/2.3.x/config/). -### Database - -To initialize the database, run this command: - -```bash -(venv) $ python -m flask --app board init-db -``` - -If you used the content for the `.env` file from above, then you can find a `board.sqlite` database in the root directory of your project. - ## Development Server To run the Flask development server, enter this command in your terminal while being in the root directory of your project: From 011e237fe85b00cd33f18b880ec8fc6498373ab9 Mon Sep 17 00:00:00 2001 From: KateFinegan Date: Mon, 11 Dec 2023 15:54:48 -0700 Subject: [PATCH 5/5] Renamed folders to match slugs --- {flask-series-part-2 => flask-database}/README.md | 0 {flask-series-part-2 => flask-database}/board/__init__.py | 0 {flask-series-part-2 => flask-database}/board/database.py | 0 {flask-series-part-1 => flask-database}/board/pages.py | 0 {flask-series-part-2 => flask-database}/board/posts.py | 0 {flask-series-part-2 => flask-database}/board/schema.sql | 0 {flask-series-part-2 => flask-database}/board/static/styles.css | 0 .../board/templates/_navigation.html | 0 {flask-series-part-1 => flask-database}/board/templates/base.html | 0 .../board/templates/pages/about.html | 0 .../board/templates/pages/home.html | 0 .../board/templates/posts/create.html | 0 .../board/templates/posts/posts.html | 0 {flask-series-part-1 => flask-database}/requirements.txt | 0 {flask-series-part-3 => flask-logging}/README.md | 0 {flask-series-part-3 => flask-logging}/board/__init__.py | 0 {flask-series-part-3 => flask-logging}/board/database.py | 0 {flask-series-part-3 => flask-logging}/board/errors.py | 0 {flask-series-part-2 => flask-logging}/board/pages.py | 0 {flask-series-part-3 => flask-logging}/board/posts.py | 0 {flask-series-part-3 => flask-logging}/board/schema.sql | 0 {flask-series-part-3 => flask-logging}/board/static/styles.css | 0 .../board/templates/_navigation.html | 0 {flask-series-part-3 => flask-logging}/board/templates/base.html | 0 .../board/templates/errors/404.html | 0 .../board/templates/pages/about.html | 0 .../board/templates/pages/home.html | 0 .../board/templates/posts/create.html | 0 .../board/templates/posts/posts.html | 0 {flask-series-part-2 => flask-logging}/requirements.txt | 0 {flask-series-part-1 => flask-project}/README.md | 0 {flask-series-part-1 => flask-project}/board/__init__.py | 0 {flask-series-part-3 => flask-project}/board/pages.py | 0 {flask-series-part-1 => flask-project}/board/static/styles.css | 0 .../board/templates/_navigation.html | 0 {flask-series-part-2 => flask-project}/board/templates/base.html | 0 .../board/templates/pages/about.html | 0 .../board/templates/pages/home.html | 0 {flask-series-part-3 => flask-project}/requirements.txt | 0 39 files changed, 0 insertions(+), 0 deletions(-) rename {flask-series-part-2 => flask-database}/README.md (100%) rename {flask-series-part-2 => flask-database}/board/__init__.py (100%) rename {flask-series-part-2 => flask-database}/board/database.py (100%) rename {flask-series-part-1 => flask-database}/board/pages.py (100%) rename {flask-series-part-2 => flask-database}/board/posts.py (100%) rename {flask-series-part-2 => flask-database}/board/schema.sql (100%) rename {flask-series-part-2 => flask-database}/board/static/styles.css (100%) rename {flask-series-part-2 => flask-database}/board/templates/_navigation.html (100%) rename {flask-series-part-1 => flask-database}/board/templates/base.html (100%) rename {flask-series-part-1 => flask-database}/board/templates/pages/about.html (100%) rename {flask-series-part-1 => flask-database}/board/templates/pages/home.html (100%) rename {flask-series-part-2 => flask-database}/board/templates/posts/create.html (100%) rename {flask-series-part-2 => flask-database}/board/templates/posts/posts.html (100%) rename {flask-series-part-1 => flask-database}/requirements.txt (100%) rename {flask-series-part-3 => flask-logging}/README.md (100%) rename {flask-series-part-3 => flask-logging}/board/__init__.py (100%) rename {flask-series-part-3 => flask-logging}/board/database.py (100%) rename {flask-series-part-3 => flask-logging}/board/errors.py (100%) rename {flask-series-part-2 => flask-logging}/board/pages.py (100%) rename {flask-series-part-3 => flask-logging}/board/posts.py (100%) rename {flask-series-part-3 => flask-logging}/board/schema.sql (100%) rename {flask-series-part-3 => flask-logging}/board/static/styles.css (100%) rename {flask-series-part-3 => flask-logging}/board/templates/_navigation.html (100%) rename {flask-series-part-3 => flask-logging}/board/templates/base.html (100%) rename {flask-series-part-3 => flask-logging}/board/templates/errors/404.html (100%) rename {flask-series-part-2 => flask-logging}/board/templates/pages/about.html (100%) rename {flask-series-part-2 => flask-logging}/board/templates/pages/home.html (100%) rename {flask-series-part-3 => flask-logging}/board/templates/posts/create.html (100%) rename {flask-series-part-3 => flask-logging}/board/templates/posts/posts.html (100%) rename {flask-series-part-2 => flask-logging}/requirements.txt (100%) rename {flask-series-part-1 => flask-project}/README.md (100%) rename {flask-series-part-1 => flask-project}/board/__init__.py (100%) rename {flask-series-part-3 => flask-project}/board/pages.py (100%) rename {flask-series-part-1 => flask-project}/board/static/styles.css (100%) rename {flask-series-part-1 => flask-project}/board/templates/_navigation.html (100%) rename {flask-series-part-2 => flask-project}/board/templates/base.html (100%) rename {flask-series-part-3 => flask-project}/board/templates/pages/about.html (100%) rename {flask-series-part-3 => flask-project}/board/templates/pages/home.html (100%) rename {flask-series-part-3 => flask-project}/requirements.txt (100%) diff --git a/flask-series-part-2/README.md b/flask-database/README.md similarity index 100% rename from flask-series-part-2/README.md rename to flask-database/README.md diff --git a/flask-series-part-2/board/__init__.py b/flask-database/board/__init__.py similarity index 100% rename from flask-series-part-2/board/__init__.py rename to flask-database/board/__init__.py diff --git a/flask-series-part-2/board/database.py b/flask-database/board/database.py similarity index 100% rename from flask-series-part-2/board/database.py rename to flask-database/board/database.py diff --git a/flask-series-part-1/board/pages.py b/flask-database/board/pages.py similarity index 100% rename from flask-series-part-1/board/pages.py rename to flask-database/board/pages.py diff --git a/flask-series-part-2/board/posts.py b/flask-database/board/posts.py similarity index 100% rename from flask-series-part-2/board/posts.py rename to flask-database/board/posts.py diff --git a/flask-series-part-2/board/schema.sql b/flask-database/board/schema.sql similarity index 100% rename from flask-series-part-2/board/schema.sql rename to flask-database/board/schema.sql diff --git a/flask-series-part-2/board/static/styles.css b/flask-database/board/static/styles.css similarity index 100% rename from flask-series-part-2/board/static/styles.css rename to flask-database/board/static/styles.css diff --git a/flask-series-part-2/board/templates/_navigation.html b/flask-database/board/templates/_navigation.html similarity index 100% rename from flask-series-part-2/board/templates/_navigation.html rename to flask-database/board/templates/_navigation.html diff --git a/flask-series-part-1/board/templates/base.html b/flask-database/board/templates/base.html similarity index 100% rename from flask-series-part-1/board/templates/base.html rename to flask-database/board/templates/base.html diff --git a/flask-series-part-1/board/templates/pages/about.html b/flask-database/board/templates/pages/about.html similarity index 100% rename from flask-series-part-1/board/templates/pages/about.html rename to flask-database/board/templates/pages/about.html diff --git a/flask-series-part-1/board/templates/pages/home.html b/flask-database/board/templates/pages/home.html similarity index 100% rename from flask-series-part-1/board/templates/pages/home.html rename to flask-database/board/templates/pages/home.html diff --git a/flask-series-part-2/board/templates/posts/create.html b/flask-database/board/templates/posts/create.html similarity index 100% rename from flask-series-part-2/board/templates/posts/create.html rename to flask-database/board/templates/posts/create.html diff --git a/flask-series-part-2/board/templates/posts/posts.html b/flask-database/board/templates/posts/posts.html similarity index 100% rename from flask-series-part-2/board/templates/posts/posts.html rename to flask-database/board/templates/posts/posts.html diff --git a/flask-series-part-1/requirements.txt b/flask-database/requirements.txt similarity index 100% rename from flask-series-part-1/requirements.txt rename to flask-database/requirements.txt diff --git a/flask-series-part-3/README.md b/flask-logging/README.md similarity index 100% rename from flask-series-part-3/README.md rename to flask-logging/README.md diff --git a/flask-series-part-3/board/__init__.py b/flask-logging/board/__init__.py similarity index 100% rename from flask-series-part-3/board/__init__.py rename to flask-logging/board/__init__.py diff --git a/flask-series-part-3/board/database.py b/flask-logging/board/database.py similarity index 100% rename from flask-series-part-3/board/database.py rename to flask-logging/board/database.py diff --git a/flask-series-part-3/board/errors.py b/flask-logging/board/errors.py similarity index 100% rename from flask-series-part-3/board/errors.py rename to flask-logging/board/errors.py diff --git a/flask-series-part-2/board/pages.py b/flask-logging/board/pages.py similarity index 100% rename from flask-series-part-2/board/pages.py rename to flask-logging/board/pages.py diff --git a/flask-series-part-3/board/posts.py b/flask-logging/board/posts.py similarity index 100% rename from flask-series-part-3/board/posts.py rename to flask-logging/board/posts.py diff --git a/flask-series-part-3/board/schema.sql b/flask-logging/board/schema.sql similarity index 100% rename from flask-series-part-3/board/schema.sql rename to flask-logging/board/schema.sql diff --git a/flask-series-part-3/board/static/styles.css b/flask-logging/board/static/styles.css similarity index 100% rename from flask-series-part-3/board/static/styles.css rename to flask-logging/board/static/styles.css diff --git a/flask-series-part-3/board/templates/_navigation.html b/flask-logging/board/templates/_navigation.html similarity index 100% rename from flask-series-part-3/board/templates/_navigation.html rename to flask-logging/board/templates/_navigation.html diff --git a/flask-series-part-3/board/templates/base.html b/flask-logging/board/templates/base.html similarity index 100% rename from flask-series-part-3/board/templates/base.html rename to flask-logging/board/templates/base.html diff --git a/flask-series-part-3/board/templates/errors/404.html b/flask-logging/board/templates/errors/404.html similarity index 100% rename from flask-series-part-3/board/templates/errors/404.html rename to flask-logging/board/templates/errors/404.html diff --git a/flask-series-part-2/board/templates/pages/about.html b/flask-logging/board/templates/pages/about.html similarity index 100% rename from flask-series-part-2/board/templates/pages/about.html rename to flask-logging/board/templates/pages/about.html diff --git a/flask-series-part-2/board/templates/pages/home.html b/flask-logging/board/templates/pages/home.html similarity index 100% rename from flask-series-part-2/board/templates/pages/home.html rename to flask-logging/board/templates/pages/home.html diff --git a/flask-series-part-3/board/templates/posts/create.html b/flask-logging/board/templates/posts/create.html similarity index 100% rename from flask-series-part-3/board/templates/posts/create.html rename to flask-logging/board/templates/posts/create.html diff --git a/flask-series-part-3/board/templates/posts/posts.html b/flask-logging/board/templates/posts/posts.html similarity index 100% rename from flask-series-part-3/board/templates/posts/posts.html rename to flask-logging/board/templates/posts/posts.html diff --git a/flask-series-part-2/requirements.txt b/flask-logging/requirements.txt similarity index 100% rename from flask-series-part-2/requirements.txt rename to flask-logging/requirements.txt diff --git a/flask-series-part-1/README.md b/flask-project/README.md similarity index 100% rename from flask-series-part-1/README.md rename to flask-project/README.md diff --git a/flask-series-part-1/board/__init__.py b/flask-project/board/__init__.py similarity index 100% rename from flask-series-part-1/board/__init__.py rename to flask-project/board/__init__.py diff --git a/flask-series-part-3/board/pages.py b/flask-project/board/pages.py similarity index 100% rename from flask-series-part-3/board/pages.py rename to flask-project/board/pages.py diff --git a/flask-series-part-1/board/static/styles.css b/flask-project/board/static/styles.css similarity index 100% rename from flask-series-part-1/board/static/styles.css rename to flask-project/board/static/styles.css diff --git a/flask-series-part-1/board/templates/_navigation.html b/flask-project/board/templates/_navigation.html similarity index 100% rename from flask-series-part-1/board/templates/_navigation.html rename to flask-project/board/templates/_navigation.html diff --git a/flask-series-part-2/board/templates/base.html b/flask-project/board/templates/base.html similarity index 100% rename from flask-series-part-2/board/templates/base.html rename to flask-project/board/templates/base.html diff --git a/flask-series-part-3/board/templates/pages/about.html b/flask-project/board/templates/pages/about.html similarity index 100% rename from flask-series-part-3/board/templates/pages/about.html rename to flask-project/board/templates/pages/about.html diff --git a/flask-series-part-3/board/templates/pages/home.html b/flask-project/board/templates/pages/home.html similarity index 100% rename from flask-series-part-3/board/templates/pages/home.html rename to flask-project/board/templates/pages/home.html diff --git a/flask-series-part-3/requirements.txt b/flask-project/requirements.txt similarity index 100% rename from flask-series-part-3/requirements.txt rename to flask-project/requirements.txt