MIL-002 Lecture steps: URL paths, HTML, decorators, authentication #24

Merged
Tirsvad merged 3 commits from mil-002-lecture-steps into main 2026-11-06 05:47:50 +01:00
4 changed files with 104 additions and 81 deletions
Showing only changes of commit 34e376bea2 - Show all commits

No files matched your search

@@ -4,11 +4,47 @@
converter.
"""
from flask import Flask
from flask import Blueprint, Flask
from markupsafe import escape
from higher_lower.constants import HOST, PORT
## Blueprint that holds the views of this lecture step.
_blueprint = Blueprint("step_02_url_paths", __name__)
@_blueprint.route("/")
def home() -> str:
"""Answer the home route."""
return "Hello, World!"
@_blueprint.route("/bye")
def say_bye() -> str:
"""Answer the fixed route /bye."""
return "Bye"
@_blueprint.route("/username/<name>")
def greet(name: str) -> str:
"""Greet the user whose name is the variable section of the URL.
@param name The text found in the URL after /username/.
@return The greeting, with the name escaped so it cannot inject HTML.
"""
return f"Hello there {escape(name)}!"
@_blueprint.route("/username/<name>/<int:number>")
def greet_with_number(name: str, number: int) -> str:
"""Greet the user and use the converter <int:number> for a number.
@param name The text found in the URL after /username/.
@param number The integer found after the name; other text gives 404.
@return The greeting that repeats the name and the number.
"""
return f"Hello there {escape(name)}, you are {number} years old!"
def create_app() -> Flask:
"""Build the Flask application of this lecture step.
@@ -16,36 +52,7 @@ def create_app() -> Flask:
@return The configured Flask application.
"""
app = Flask(__name__)
@app.route("/")
def home() -> str:
"""Answer the home route."""
return "Hello, World!"
@app.route("/bye")
def say_bye() -> str:
"""Answer the fixed route /bye."""
return "Bye"
@app.route("/username/<name>")
def greet(name: str) -> str:
"""Greet the user whose name is the variable section of the URL.
@param name The text found in the URL after /username/.
@return The greeting, with the name escaped so it cannot inject HTML.
"""
return f"Hello there {escape(name)}!"
@app.route("/username/<name>/<int:number>")
def greet_with_number(name: str, number: int) -> str:
"""Greet the user and use the converter <int:number> for a number.
@param name The text found in the URL after /username/.
@param number The integer found after the name; other text gives 404.
@return The greeting that repeats the name and the number.
"""
return f"Hello there {escape(name)}, you are {number} years old!"
app.register_blueprint(_blueprint)
return app
@@ -3,7 +3,7 @@
@brief A route that returns a heading, a paragraph and two images as HTML.
"""
from flask import Flask
from flask import Blueprint, Flask
from higher_lower.constants import HOST, LECTURE_IMAGE_WIDTH, PORT, STILL_IMAGE
@@ -11,29 +11,34 @@ from higher_lower.constants import HOST, LECTURE_IMAGE_WIDTH, PORT, STILL_IMAGE
ANIMATED_IMAGE: str = STILL_IMAGE.replace("_s.gif", ".gif")
## Blueprint that holds the views of this lecture step.
_blueprint = Blueprint("step_03_html", __name__)
@_blueprint.route("/")
def home() -> str:
"""Return structured HTML instead of a plain string.
The Python string uses double quotes and the HTML attributes use single
quotes, so the two never end each other.
@return A centred heading, a paragraph, a still picture and a GIF.
"""
return (
"<h1 style='text-align: center'>Hello, World!</h1>"
"<p>This is a paragraph.</p>"
f"<img src='{STILL_IMAGE}' width={LECTURE_IMAGE_WIDTH}>"
f"<img src='{ANIMATED_IMAGE}' width={LECTURE_IMAGE_WIDTH}>"
)
def create_app() -> Flask:
"""Build the Flask application of this lecture step.
@return The configured Flask application.
"""
app = Flask(__name__)
@app.route("/")
def home() -> str:
"""Return structured HTML instead of a plain string.
The Python string uses double quotes and the HTML attributes use single
quotes, so the two never end each other.
@return A centred heading, a paragraph, a still picture and a GIF.
"""
return (
"<h1 style='text-align: center'>Hello, World!</h1>"
"<p>This is a paragraph.</p>"
f"<img src='{STILL_IMAGE}' width={LECTURE_IMAGE_WIDTH}>"
f"<img src='{ANIMATED_IMAGE}' width={LECTURE_IMAGE_WIDTH}>"
)
app.register_blueprint(_blueprint)
return app
@@ -7,7 +7,7 @@ the /bye route.
from collections.abc import Callable
from functools import wraps
from flask import Flask
from flask import Blueprint, Flask
from higher_lower.constants import HOST, PORT
@@ -54,26 +54,32 @@ def make_underlined(function: Callable[..., str]) -> Callable[..., str]:
return _wrap_in_tag(function, "u")
## Blueprint that holds the views of this lecture step.
_blueprint = Blueprint("step_04_decorators", __name__)
@_blueprint.route("/")
def home() -> str:
"""Answer the home route."""
return "Hello, World!"
@_blueprint.route("/bye")
@make_bold
@make_emphasis
@make_underlined
def say_bye() -> str:
"""Answer /bye with bold, emphasised and underlined text."""
return "Bye"
def create_app() -> Flask:
"""Build the Flask application of this lecture step.
@return The configured Flask application.
"""
app = Flask(__name__)
@app.route("/")
def home() -> str:
"""Answer the home route."""
return "Hello, World!"
@app.route("/bye")
@make_bold
@make_emphasis
@make_underlined
def say_bye() -> str:
"""Answer /bye with bold, emphasised and underlined text."""
return "Bye"
app.register_blueprint(_blueprint)
return app
@@ -7,7 +7,7 @@ only for a logged-in user.
from collections.abc import Callable
from functools import wraps
from flask import Flask
from flask import Blueprint, Flask
from markupsafe import escape
from higher_lower.constants import HOST, PORT
@@ -57,28 +57,33 @@ def create_blog_post(user: User) -> str:
return f"This is {user.name}'s new blog post."
## Blueprint that holds the views of this lecture step.
_blueprint = Blueprint("step_05_authenticated", __name__)
@_blueprint.route("/")
def home() -> str:
"""Show the result of create_blog_post for a user in and out."""
lines = []
for name, logged_in in (("Angela", True), ("Bob", False)):
user = User(name)
user.is_logged_in = logged_in
state = "logged in" if logged_in else "logged out"
post = create_blog_post(user)
lines.append(
f"<p>{escape(name)} is {state}: "
f"{escape(post) if post else 'no post created'}</p>"
)
return "<h1>is_authenticated</h1>" + "".join(lines)
def create_app() -> Flask:
"""Build the Flask application of this lecture step.
@return The configured Flask application.
"""
app = Flask(__name__)
@app.route("/")
def home() -> str:
"""Show the result of create_blog_post for a user in and out."""
lines = []
for name, logged_in in (("Angela", True), ("Bob", False)):
user = User(name)
user.is_logged_in = logged_in
state = "logged in" if logged_in else "logged out"
post = create_blog_post(user)
lines.append(
f"<p>{escape(name)} is {state}: "
f"{escape(post) if post else 'no post created'}</p>"
)
return "<h1>is_authenticated</h1>" + "".join(lines)
app.register_blueprint(_blueprint)
return app