"""Health data routes: summary / steps / heart-rate / sleep / activities.""" import datetime from flask import Blueprint, request, g, jsonify from auth import require_auth from services import health as health_svc from services import settings as settings_svc from services import fitness_age bp = Blueprint("health", __name__) def _range(): return request.args.get("startDate"), request.args.get("endDate") @bp.route("/summary", methods=["GET"]) @require_auth def summary(): s, e = _range() return jsonify(health_svc.get_summary(g.user_id, s, e)) @bp.route("/steps", methods=["GET"]) @require_auth def steps(): s, e = _range() return jsonify(health_svc.get_steps(g.user_id, s, e)) @bp.route("/heart-rate", methods=["GET"]) @require_auth def heart_rate(): s, e = _range() return jsonify(health_svc.get_heart_rate(g.user_id, s, e)) @bp.route("/sleep", methods=["GET"]) @require_auth def sleep(): s, e = _range() return jsonify(health_svc.get_sleep(g.user_id, s, e)) @bp.route("/activities", methods=["GET"]) @require_auth def activities(): s, e = _range() return jsonify(health_svc.get_activities(g.user_id, s, e)) @bp.route("/fitness-age", methods=["GET"]) @require_auth def body_age(): """身体年龄, computed from the profile plus the most recent readings. VO2max only refreshes after an outdoor run or ride, so the search window is wide: the last recorded value is still the current one. """ profile = settings_svc.get_raw(g.user_id) start = (datetime.date.today() - datetime.timedelta(days=180)).isoformat() days = health_svc.get_summary(g.user_id, start, None) def latest(key): for day in reversed(days): if day.get(key): return day[key] return None return jsonify(fitness_age.estimate( age=settings_svc.age_from(profile["birth_date"]), sex=profile["sex"], vo2max=latest("vo2max"), resting_hr=latest("heartRate"), bmi=settings_svc.bmi_from(profile["height_cm"], profile["weight_kg"]), )) @bp.route("/badges", methods=["GET"]) @require_auth def badges(): """Earned badges (奖励), most recent first.""" return jsonify(health_svc.get_badges(g.user_id)) @bp.route("/personal-records", methods=["GET"]) @require_auth def personal_records(): return jsonify(health_svc.get_personal_records(g.user_id))