Add running fitness history and configurable heart rate zones

This commit is contained in:
Peter Stockings
2026-10-22 23:20:35 +11:00
parent b8eb6d10f8
commit 95e751d05c
15 changed files with 534 additions and 2 deletions
+63 -1
View File
@@ -1,6 +1,6 @@
"""Private training preferences and session observations."""
from flask import Blueprint, abort, flash, redirect, request, url_for
from flask import Blueprint, abort, flash, jsonify, redirect, render_template, request, url_for
from flask_login import current_user, login_required
from .extensions import db
@@ -9,6 +9,68 @@ from .models import Activity
training = Blueprint("training", __name__)
@training.get("/fitness")
@login_required
def fitness():
from .fitness import history
return render_template("fitness.html", data=history(current_user))
@training.get("/fitness/data")
@login_required
def fitness_data():
from .fitness import history
return jsonify(history(current_user))
@training.app_context_processor
def fitness_helpers():
from .fitness import effort
from .heart_rate import zones
return {"run_effort": effort, "fitness_zones": zones}
@training.post("/training/zones")
@login_required
def zones():
from datetime import date, datetime
from zoneinfo import ZoneInfo
mode = request.form.get("mode")
if mode not in {"auto", "max", "custom"}:
abort(400)
config = {"mode": mode}
try:
birthday = request.form.get("birthday", "").strip()
if birthday:
birthday_date = date.fromisoformat(birthday)
today = datetime.now(ZoneInfo(current_user.timezone)).date()
age = today.year - birthday_date.year - ((today.month, today.day) <
(birthday_date.month, birthday_date.day))
if not 5 <= age <= 110:
abort(400)
config["birthday"] = birthday
if mode == "max":
maximum = int(request.form.get("max_hr", ""))
if not 100 <= maximum <= 230:
abort(400)
config["max_hr"] = maximum
if mode == "custom":
boundaries = [int(request.form.get(f"z{i}", "")) for i in range(2, 6)]
if not 30 <= boundaries[0] < boundaries[1] < boundaries[2] < boundaries[3] <= 230:
abort(400)
config["boundaries"] = boundaries
except (ValueError, TypeError):
abort(400)
current_user.hr_zones = config
db.session.commit()
flash("Fitness zones saved. Your full fitness history recalculates automatically.")
return redirect(url_for("training.fitness"))
@training.post("/training/bands")
@login_required
def bands():