Read distance, calories, max_rpm, min_rpm, average_rpm etc from workout rather then recalculating on each render, still need to modify add workout endpoint to calculate properties and set on workout
This commit is contained in:
126
app.py
126
app.py
@@ -14,6 +14,7 @@ import sparklines
|
||||
app = Flask(__name__)
|
||||
# TODO CHANGE SECRET KEY TO ENVIRONMENT VARIABLE
|
||||
app.config['SECRET_KEY'] = 'secret!'
|
||||
app.config["SQLALCHEMY_ECHO"] = False # True for debugging
|
||||
uri = os.getenv("DATABASE_URL")
|
||||
if uri and uri.startswith("postgres://"):
|
||||
uri = uri.replace("postgres://", "postgresql://", 1)
|
||||
@@ -50,8 +51,23 @@ class Workout(db.Model):
|
||||
created_at = db.Column(db.DateTime, nullable=False, default=db.func.now())
|
||||
bike_id = db.Column(db.Integer, db.ForeignKey(
|
||||
'bikes.id', ondelete='CASCADE'), nullable=False)
|
||||
started_at = db.Column(db.DateTime, nullable=False)
|
||||
duration = db.Column(db.Numeric, nullable=False)
|
||||
average_rpm = db.Column(db.Numeric, nullable=False)
|
||||
min_rpm = db.Column(db.Integer, nullable=False)
|
||||
max_rpm = db.Column(db.Integer, nullable=False)
|
||||
calories = db.Column(db.Numeric, nullable=False)
|
||||
distance = db.Column(db.Numeric, nullable=False)
|
||||
average_bpm = db.Column(db.Numeric, nullable=False)
|
||||
min_bpm = db.Column(db.Integer, nullable=False)
|
||||
max_bpm = db.Column(db.Integer, nullable=False)
|
||||
is_heart_rate_available = db.Column(
|
||||
db.Boolean, nullable=False, default=False)
|
||||
is_cadence_available = db.Column(db.Boolean, nullable=False, default=False)
|
||||
cadence_readings = db.relationship(
|
||||
'CadenceReading', backref='workout', lazy=True)
|
||||
heart_rate_readings = db.relationship(
|
||||
'HeartRateReading', backref='workout', lazy=True)
|
||||
bike = db.relationship('Bike', backref='workouts', lazy=True)
|
||||
|
||||
|
||||
@@ -154,39 +170,39 @@ def workouts(user_id):
|
||||
|
||||
@app.route('/user/<int:user_id>/workout/<int:workout_id>/<string:graph_type>', methods=['GET', 'DELETE'])
|
||||
def workout(user_id, workout_id, graph_type):
|
||||
workout = Workout.query.filter_by(user_id=user_id, id=workout_id).first()
|
||||
if workout:
|
||||
# Get the cadence readings for the workout
|
||||
cadence_readings = CadenceReading.query.filter_by(
|
||||
workout_id=workout_id).all()
|
||||
if cadence_readings:
|
||||
x_values = [reading.created_at for reading in cadence_readings]
|
||||
if graph_type == 'cadence':
|
||||
y_values = [reading.rpm for reading in cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Cadence (RPM)', filename='cadence'), 200
|
||||
elif graph_type == 'speed':
|
||||
y_values = [reading.speed for reading in cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Speed (KPH)', filename='speed'), 200
|
||||
elif graph_type == 'distance':
|
||||
y_values = [reading.distance for reading in cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Distance (KM)', filename='distance'), 200
|
||||
elif graph_type == 'calories':
|
||||
y_values = [reading.calories for reading in cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Calories (KCAL)', filename='calories'), 200
|
||||
elif graph_type == 'power':
|
||||
y_values = [reading.power for reading in cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Power (WATTS)', filename='power'), 200
|
||||
heart_rate_readings = HeartRateReading.query.filter_by(
|
||||
workout_id=workout_id).all()
|
||||
if heart_rate_readings:
|
||||
x_values = [reading.created_at for reading in heart_rate_readings]
|
||||
y_values = [reading.bpm for reading in heart_rate_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Heart Rate (BPM)', filename='heart_rate'), 200
|
||||
else:
|
||||
return jsonify({'message': 'No cadence readings for workout {}.'.format(workout_id)}), 404
|
||||
else:
|
||||
workout = Workout.query.filter_by(user_id=user_id, id=workout_id).join(
|
||||
Workout.cadence_readings).join(Workout.heart_rate_readings).first()
|
||||
|
||||
if not workout:
|
||||
return jsonify({'message': 'Workout {} not found for user {}.'.format(workout_id, user_id)}), 404
|
||||
|
||||
if workout.is_cadence_available:
|
||||
x_values = [reading.created_at for reading in workout.cadence_readings]
|
||||
if graph_type == 'cadence':
|
||||
y_values = [reading.rpm for reading in workout.cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Cadence (RPM)', filename='cadence'), 200
|
||||
elif graph_type == 'speed':
|
||||
y_values = [reading.speed for reading in workout.cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Speed (KPH)', filename='speed'), 200
|
||||
elif graph_type == 'distance':
|
||||
y_values = [
|
||||
reading.distance for reading in workout.cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Distance (KM)', filename='distance'), 200
|
||||
elif graph_type == 'calories':
|
||||
y_values = [
|
||||
reading.calories for reading in workout.cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Calories (KCAL)', filename='calories'), 200
|
||||
elif graph_type == 'power':
|
||||
y_values = [reading.power for reading in workout.cadence_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Power (WATTS)', filename='power'), 200
|
||||
if workout.is_heart_rate_available:
|
||||
x_values = [
|
||||
reading.created_at for reading in workout.heart_rate_readings]
|
||||
y_values = [reading.bpm for reading in workout.heart_rate_readings]
|
||||
return create_graph(x_values=x_values, y_values=y_values, y_label='Heart Rate (BPM)', filename='heart_rate'), 200
|
||||
|
||||
return jsonify({'message': 'Unable to generate {} for workout {}.'.format(graph_type, workout_id)}), 409
|
||||
|
||||
|
||||
@app.route('/user/<int:user_id>/workout/<int:workout_id>/view', methods=['GET'])
|
||||
def view_workout(user_id, workout_id):
|
||||
@@ -296,32 +312,28 @@ def get_workouts_for_user(user_id):
|
||||
workouts_data = []
|
||||
workouts = Workout.query.filter_by(user_id=user_id).order_by(
|
||||
Workout.created_at.desc()).all()
|
||||
|
||||
for workout in workouts:
|
||||
cadence_readings = CadenceReading.query.filter_by(
|
||||
workout_id=workout.id).all()
|
||||
|
||||
if cadence_readings:
|
||||
start_time = min(
|
||||
reading.created_at for reading in cadence_readings)
|
||||
end_time = max(
|
||||
reading.created_at for reading in cadence_readings)
|
||||
duration = end_time - start_time
|
||||
average_rpm = sum(
|
||||
reading.rpm for reading in cadence_readings) / len(cadence_readings)
|
||||
calories = cadence_readings[-1].calories
|
||||
distance = cadence_readings[-1].distance
|
||||
duration = timedelta(
|
||||
seconds=int(workout.duration)) if workout.duration else timedelta(seconds=0)
|
||||
average_rpm = workout.average_rpm if workout.average_rpm else 0
|
||||
min_rpm = workout.min_rpm if workout.min_rpm else 0
|
||||
max_rpm = workout.max_rpm if workout.max_rpm else 0
|
||||
calories = workout.calories if workout.calories else 0
|
||||
distance = workout.distance if workout.distance else 0
|
||||
average_bpm = workout.average_bpm if workout.average_bpm else 0
|
||||
min_bpm = workout.min_bpm if workout.min_bpm else 0
|
||||
max_bpm = workout.max_bpm if workout.max_bpm else 0
|
||||
is_heart_rate_available = workout.is_heart_rate_available
|
||||
is_cadence_available = workout.is_cadence_available
|
||||
start_time = workout.started_at
|
||||
|
||||
selected_graph_types = ['speed']
|
||||
is_heart_rate_available = False
|
||||
heart_rate_readings = HeartRateReading.query.filter_by(
|
||||
workout_id=workout.id).all()
|
||||
average_bpm = 0
|
||||
if heart_rate_readings:
|
||||
selected_graph_types.append('heart_rate')
|
||||
is_heart_rate_available = True
|
||||
average_bpm = sum(heartrate.bpm for heartrate in heart_rate_readings) / \
|
||||
len(heart_rate_readings)
|
||||
selected_graph_types = ['speed']
|
||||
if is_heart_rate_available:
|
||||
selected_graph_types.append('heart_rate')
|
||||
|
||||
if is_cadence_available or is_heart_rate_available:
|
||||
workouts_data.append({
|
||||
'id': workout.id,
|
||||
'user_id': user_id,
|
||||
@@ -331,13 +343,19 @@ def get_workouts_for_user(user_id):
|
||||
'duration': format_duration(duration),
|
||||
'duration_minutes': duration.total_seconds() / 60,
|
||||
'average_rpm': int(average_rpm),
|
||||
'min_rpm': int(min_rpm),
|
||||
'max_rpm': int(max_rpm),
|
||||
'calories': int(calories),
|
||||
'distance': int(distance),
|
||||
'bike_display_name': workout.bike.display_name,
|
||||
'selected_graph_types': selected_graph_types,
|
||||
'is_heart_rate_available': is_heart_rate_available,
|
||||
'average_bpm': int(average_bpm)
|
||||
'is_cadence_available': is_cadence_available,
|
||||
'average_bpm': int(average_bpm),
|
||||
'min_bpm': int(min_bpm),
|
||||
'max_bpm': int(max_bpm),
|
||||
})
|
||||
|
||||
return workouts_data
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user