feat: Refactor workout functionality into blueprint

- Moved workout-related routes (create/delete/edit workouts, topsets, tags, start dates, show workout) from `app.py` into a new blueprint at `routes/workout.py`.
- Integrated workout view model logic from `features/workout.py` directly into `routes/workout.py` helper function `_get_workout_view_model`.
- Removed `features/workout.py` and the corresponding class instantiation in `db.py`.
- Registered the new `workout_bp` blueprint in `app.py`.
- Removed the original workout route definitions from `app.py`.
- Updated `url_for` calls in relevant templates (`workout.html`, `person_overview.html`, `partials/workout_tags.html`, `partials/topset.html`, `partials/start_date.html`, `partials/new_set_form.html`, `notes.html`, `calendar.html`) to reference the new blueprint endpoints (e.g., `workout.create_workout`).
- Updated `templates/changelog/changelog.html` to document this refactoring.
This commit is contained in:
Peter Stockings
2025-03-31 22:38:48 +11:00
parent 78436b230b
commit eaeb4ab2c8
13 changed files with 276 additions and 242 deletions

135
app.py
View File

@@ -9,6 +9,7 @@ from routes.auth import auth, get_person_by_id
from routes.changelog import changelog_bp
from routes.calendar import calendar_bp # Import the new calendar blueprint
from routes.notes import notes_bp # Import the new notes blueprint
from routes.workout import workout_bp # Import the new workout blueprint
from extensions import db
from utils import convert_str_to_date, generate_plot
from flask_htmx import HTMX
@@ -38,6 +39,7 @@ app.register_blueprint(auth, url_prefix='/auth')
app.register_blueprint(changelog_bp, url_prefix='/changelog')
app.register_blueprint(calendar_bp) # Register the calendar blueprint
app.register_blueprint(notes_bp) # Register the notes blueprint
app.register_blueprint(workout_bp) # Register the workout blueprint
@app.after_request
def response_minify(response):
@@ -131,99 +133,6 @@ def person_overview(person_id):
return render_template('person_overview.html', **render_args), 200, {"HX-Push-Url": url_for('person_overview', person_id=person_id, min_date=min_date, max_date=max_date, exercise_id=selected_exercise_ids), "HX-Trigger": "refreshStats"}
# Route moved to routes/notes.py
@ app.route("/person/<int:person_id>/workout", methods=['POST'])
def create_workout(person_id):
new_workout_id = db.create_workout(person_id)
workout = db.get_workout(person_id, new_workout_id)
(person_tags, workout_tags, selected_workout_tag_ids) = db.get_workout_tags(
person_id, new_workout_id)
view_model = db.workout.get(person_id, new_workout_id)
return render_block(app.jinja_env, 'workout.html', 'content', **view_model)
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/delete", methods=['GET'])
@ validate_workout
def delete_workout(person_id, workout_id):
db.delete_workout(workout_id)
return redirect(url_for('calendar.get_calendar', person_id=person_id))
#return "", 200, {"HX-Trigger": "updatedPeople", "HX-Push-Url": url_for('calendar.get_calendar', person_id=person_id)}
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/start_date_edit_form", methods=['GET'])
@ validate_workout
def get_workout_start_date_edit_form(person_id, workout_id):
workout = db.get_workout(person_id, workout_id)
return render_template('partials/start_date.html', person_id=person_id, workout_id=workout_id, start_date=workout['start_date'], is_edit=True)
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/start_date", methods=['PUT'])
@ validate_workout
def update_workout_start_date(person_id, workout_id):
new_start_date = request.form.get('start-date')
db.update_workout_start_date(workout_id, new_start_date)
return render_template('partials/start_date.html', person_id=person_id, workout_id=workout_id, start_date=convert_str_to_date(new_start_date, '%Y-%m-%d'))
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/start_date", methods=['GET'])
@ validate_workout
def get_workout_start_date(person_id, workout_id):
workout = db.get_workout(person_id, workout_id)
return render_template('partials/start_date.html', person_id=person_id, workout_id=workout_id, start_date=workout['start_date'])
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/topset/<int:topset_id>", methods=['GET'])
@ validate_topset
def get_topset(person_id, workout_id, topset_id):
topset = db.get_topset(topset_id)
return render_template('partials/topset.html', person_id=person_id, workout_id=workout_id, topset_id=topset_id, exercise_id=topset['exercise_id'], exercise_name=topset['exercise_name'], repetitions=topset['repetitions'], weight=topset['weight'])
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/topset/<int:topset_id>/edit_form", methods=['GET'])
@ validate_topset
def get_topset_edit_form(person_id, workout_id, topset_id):
exercises = db.get_all_exercises()
topset = db.get_topset(topset_id)
return render_template('partials/topset.html', person_id=person_id, workout_id=workout_id, topset_id=topset_id, exercises=exercises, exercise_id=topset['exercise_id'], exercise_name=topset['exercise_name'], repetitions=topset['repetitions'], weight=topset['weight'], is_edit=True)
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/topset", methods=['POST'])
@ validate_workout
def create_topset(person_id, workout_id):
exercise_id = request.form.get("exercise_id")
repetitions = request.form.get("repetitions")
weight = request.form.get("weight")
new_topset_id = db.create_topset(
workout_id, exercise_id, repetitions, weight)
exercise = db.get_exercise(exercise_id)
return render_template('partials/topset.html', person_id=person_id, workout_id=workout_id, topset_id=new_topset_id, exercise_id=exercise_id, exercise_name=exercise['name'], repetitions=repetitions, weight=weight), 200, {"HX-Trigger": "topsetAdded"}
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/topset/<int:topset_id>", methods=['PUT'])
@ validate_workout
def update_topset(person_id, workout_id, topset_id):
exercise_id = request.form.get("exercise_id")
repetitions = request.form.get("repetitions")
weight = request.form.get("weight")
db.update_topset(exercise_id, repetitions, weight, topset_id)
exercise = db.get_exercise(exercise_id)
return render_template('partials/topset.html', person_id=person_id, workout_id=workout_id, topset_id=topset_id, exercise_name=exercise['name'], repetitions=repetitions, weight=weight)
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/topset/<int:topset_id>/delete", methods=['DELETE'])
@ validate_topset
def delete_topset(person_id, workout_id, topset_id):
db.delete_topset(topset_id)
return ""
@ app.route("/person", methods=['POST'])
def create_person():
name = request.form.get("name")
@@ -328,38 +237,6 @@ def delete_tag(tag_id):
db.delete_tag_for_dashboard(tag_id)
return redirect(url_for('dashboard') + tag_filter)
# Routes moved to routes/notes.py
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/tag/add", methods=['POST'])
def add_tag_to_workout(person_id, workout_id):
tags_id = [int(i) for i in request.form.getlist('tag_id')]
tags = db.add_tag_for_workout(workout_id, tags_id)
return render_template('partials/workout_tags_list.html', tags=tags)
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/tag/new", methods=['POST'])
def create_new_tag_for_workout(person_id, workout_id):
tag_name = request.form.get('tag_name')
workout_tags = db.create_tag_for_workout(person_id, workout_id, tag_name)
return render_template('partials/workout_tags_list.html', workout_tags=workout_tags)
@ app.route("/person/<int:person_id>/workout/<int:workout_id>/exercise/most_recent_topset_for_exercise", methods=['GET'])
def get_most_recent_topset_for_exercise(person_id, workout_id):
exercise_id = request.args.get('exercise_id', type=int)
exercises = db.get_all_exercises()
if not exercise_id:
return render_template('partials/new_set_form.html', person_id=person_id, workout_id=workout_id, exercises=exercises)
topset = db.get_most_recent_topset_for_exercise(person_id, exercise_id)
if not topset:
return render_template('partials/new_set_form.html', person_id=person_id, workout_id=workout_id, exercises=exercises, exercise_id=exercise_id)
(repetitions, weight, exercise_name) = topset
return render_template('partials/new_set_form.html', person_id=person_id, workout_id=workout_id, exercise_id=exercise_id, exercise_name=exercise_name, repetitions=repetitions, weight=weight)
@ app.route("/person/<int:person_id>/exercise/<int:exercise_id>/sparkline", methods=['GET'])
def get_exercise_progress_for_user(person_id, exercise_id):
min_date = convert_str_to_date(request.args.get(
@@ -399,14 +276,6 @@ def get_people_graphs():
return render_template('partials/people_graphs.html', graphs=graphs, refresh_url=request.full_path)
@ app.route("/person/<int:person_id>/workout/<int:workout_id>", methods=['GET'])
def show_workout(person_id, workout_id):
view_model = db.workout.get(person_id, workout_id)
if htmx:
return render_block(app.jinja_env, 'workout.html', 'content', **view_model)
return render_template('workout.html', **view_model)
@app.route("/exercises/get")
def get_exercises():
query = request.args.get('query')