Improve badge performance
This commit is contained in:
@@ -4,12 +4,14 @@ from flask_sqlalchemy import SQLAlchemy
|
||||
from flask_migrate import Migrate
|
||||
from flask_bcrypt import Bcrypt
|
||||
from flask_login import LoginManager
|
||||
from flask_compress import Compress
|
||||
|
||||
# Initialize Flask extensions
|
||||
db = SQLAlchemy()
|
||||
migrate = Migrate()
|
||||
bcrypt = Bcrypt()
|
||||
login_manager = LoginManager()
|
||||
compress = Compress()
|
||||
|
||||
login_manager.login_view = 'auth.login'
|
||||
login_manager.login_message_category = 'info'
|
||||
@@ -26,6 +28,7 @@ def create_app():
|
||||
migrate.init_app(app, db)
|
||||
bcrypt.init_app(app)
|
||||
login_manager.init_app(app)
|
||||
compress.init_app(app)
|
||||
|
||||
# Import models here to avoid circular imports
|
||||
from app.models import User # Import the User model
|
||||
|
||||
@@ -35,12 +35,7 @@ def dashboard():
|
||||
# Calculate weekly averages via SQL
|
||||
systolic_avg, diastolic_avg, heart_rate_avg = calculate_weekly_summary_sql(current_user.id)
|
||||
|
||||
# Badges need paginated or all readings. We'll fetch all readings for badges
|
||||
# Note: To avoid huge queries, we might want a specific badge query in the future.
|
||||
# For now, let's fetch current month readings + previous as a rough approximation or keep behavior.
|
||||
# A generic query for badges:
|
||||
all_readings = Reading.query.filter_by(user_id=current_user.id).order_by(Reading.timestamp.desc()).all()
|
||||
badges = calculate_progress_badges(all_readings)
|
||||
badges = calculate_progress_badges(current_user.id, user_tz)
|
||||
|
||||
# We will default to showing the list view on initial load
|
||||
page = request.args.get('page', 1, type=int)
|
||||
@@ -248,47 +243,58 @@ def prepare_graph_data(readings):
|
||||
'heart_rate': [r.heart_rate for r in readings],
|
||||
}
|
||||
|
||||
def calculate_progress_badges(readings):
|
||||
"""Generate badges based on user activity and milestones."""
|
||||
now = datetime.utcnow().date()
|
||||
def calculate_progress_badges(user_id, user_tz):
|
||||
"""Generate badges based on user activity and milestones using optimized queries."""
|
||||
now_local = datetime.now(user_tz).date()
|
||||
badges = []
|
||||
|
||||
if not readings:
|
||||
total_readings = Reading.query.filter_by(user_id=user_id).count()
|
||||
if total_readings == 0:
|
||||
return badges
|
||||
|
||||
# Use reversed() instead of re-sorting — readings come in desc order from DB
|
||||
sorted_readings = list(reversed(readings))
|
||||
streak_count = 1
|
||||
daily_streak = True
|
||||
# Fetch only timestamps (highly optimized compared to fetching full objects)
|
||||
timestamps = db.session.query(Reading.timestamp).filter(Reading.user_id == user_id).order_by(Reading.timestamp.desc()).all()
|
||||
|
||||
previous_date = sorted_readings[0].timestamp.date()
|
||||
streak_count = 0
|
||||
if timestamps:
|
||||
distinct_dates = []
|
||||
last_date = None
|
||||
for (ts,) in timestamps:
|
||||
local_date = utc.localize(ts).astimezone(user_tz).date()
|
||||
if local_date != last_date:
|
||||
distinct_dates.append(local_date)
|
||||
last_date = local_date
|
||||
|
||||
for reading in sorted_readings[1:]:
|
||||
current_date = reading.timestamp.date()
|
||||
if distinct_dates:
|
||||
most_recent_date = distinct_dates[0]
|
||||
if (now_local - most_recent_date).days <= 1:
|
||||
streak_count = 1
|
||||
current_check_date = most_recent_date
|
||||
|
||||
for d in distinct_dates[1:]:
|
||||
if (current_check_date - d).days == 1:
|
||||
streak_count += 1
|
||||
current_check_date = d
|
||||
else:
|
||||
break
|
||||
|
||||
if (current_date - previous_date).days == 1:
|
||||
streak_count += 1
|
||||
elif (current_date - previous_date).days > 1:
|
||||
daily_streak = False
|
||||
|
||||
previous_date = current_date
|
||||
|
||||
if daily_streak and streak_count >= 1:
|
||||
if streak_count >= 1:
|
||||
badges.append(f"Current Streak: {streak_count} Days")
|
||||
if daily_streak and streak_count >= 7:
|
||||
if streak_count >= 7:
|
||||
badges.append("Logged Every Day for a Week")
|
||||
|
||||
if daily_streak and streak_count >= 30 and previous_date == now:
|
||||
if streak_count >= 30:
|
||||
badges.append("Monthly Streak")
|
||||
|
||||
if all(5 <= r.timestamp.hour < 12 for r in sorted_readings[-7:]):
|
||||
badges.append("Morning Riser: Logged Readings Every Morning for a Week")
|
||||
|
||||
if all(18 <= r.timestamp.hour <= 23 for r in sorted_readings[-7:]):
|
||||
badges.append("Night Owl: Logged Readings Every Night for a Week")
|
||||
last_7_readings = db.session.query(Reading.timestamp).filter(Reading.user_id == user_id).order_by(Reading.timestamp.desc()).limit(7).all()
|
||||
if len(last_7_readings) == 7:
|
||||
if all(5 <= utc.localize(ts).astimezone(user_tz).hour < 12 for (ts,) in last_7_readings):
|
||||
badges.append("Morning Riser: Logged Readings Every Morning for a Week")
|
||||
|
||||
if all(18 <= utc.localize(ts).astimezone(user_tz).hour <= 23 for (ts,) in last_7_readings):
|
||||
badges.append("Night Owl: Logged Readings Every Night for a Week")
|
||||
|
||||
milestones = [10, 50, 100, 500, 1000, 5000, 10000]
|
||||
highest_milestone = max((m for m in milestones if len(readings) >= m), default=None)
|
||||
highest_milestone = max((m for m in milestones if total_readings >= m), default=None)
|
||||
if highest_milestone:
|
||||
badges.append(f"{highest_milestone} Readings Logged")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user