Skip to content

Commit

Permalink
Merge pull request #19 from voynow/18-multi-user-support
Browse files Browse the repository at this point in the history
18 multi user support
  • Loading branch information
voynow authored Aug 23, 2024
2 parents 5e28cfe + ba1db24 commit 13c49e3
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 51 deletions.
28 changes: 16 additions & 12 deletions src/email_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import sib_api_v3_sdk
from dotenv import load_dotenv
from urllib3.exceptions import ProtocolError

from src.types.mid_week_analysis import MidWeekAnalysis
from src.types.training_week import TrainingWeekWithCoaching, TrainingWeekWithPlanning
Expand Down Expand Up @@ -63,7 +64,7 @@ def training_week_update_to_html(
overflow: hidden;
}
.header {
background-color: #6495ED;
background-color: #5A86D5;
color: #ffffff;
text-align: center;
padding: 20px;
Expand All @@ -76,7 +77,7 @@ def training_week_update_to_html(
padding: 20px;
}
.content h2 {
color: #6495ED;
color: #5A86D5;
font-size: 20px;
margin-bottom: 10px;
}
Expand All @@ -88,7 +89,7 @@ def training_week_update_to_html(
.content li {
margin-bottom: 10px;
padding: 15px;
border-left: 5px solid #6495ED;
border-left: 5px solid #5A86D5;
border-radius: 5px;
color: #333;
}
Expand All @@ -98,7 +99,7 @@ def training_week_update_to_html(
}
.content li.upcoming {
background-color: #f9f9f9;
border-left-color: #6495ED;
border-left-color: #5A86D5;
}
.content li strong {
display: block;
Expand All @@ -110,7 +111,7 @@ def training_week_update_to_html(
display: flex;
justify-content: space-between;
align-items: center;
background-color: #6495ED;
background-color: #5A86D5;
padding: 20px 30px;
margin-top: 20px;
border-radius: 10px;
Expand Down Expand Up @@ -241,7 +242,7 @@ def training_week_to_html(training_week_with_coaching: TrainingWeekWithCoaching)
overflow: hidden;
}
.header {
background-color: #6495ED;
background-color: #5A86D5;
color: #ffffff;
text-align: center;
padding: 20px;
Expand All @@ -254,7 +255,7 @@ def training_week_to_html(training_week_with_coaching: TrainingWeekWithCoaching)
padding: 20px;
}
.content h2 {
color: #6495ED;
color: #5A86D5;
font-size: 20px;
margin-bottom: 10px;
}
Expand All @@ -267,7 +268,7 @@ def training_week_to_html(training_week_with_coaching: TrainingWeekWithCoaching)
background-color: #f9f9f9;
margin-bottom: 10px;
padding: 15px;
border-left: 5px solid #6495ED;
border-left: 5px solid #5A86D5;
border-radius: 5px;
color: #333;
}
Expand All @@ -281,7 +282,7 @@ def training_week_to_html(training_week_with_coaching: TrainingWeekWithCoaching)
display: flex;
justify-content: space-between;
align-items: center;
background-color: #6495ED;
background-color: #5A86D5;
padding: 20px 30px;
margin-top: 20px;
border-radius: 10px;
Expand Down Expand Up @@ -355,13 +356,16 @@ def training_week_to_html(training_week_with_coaching: TrainingWeekWithCoaching)
def send_email(
subject: str,
html_content: str,
to: list = [{"email": "voynow99@gmail.com", "name": "Jamie Voynow"}],
to: Dict[str, str],
sender: Dict[str, str] = {
"name": "Jamie Voynow",
"email": "voynowtestaddress@gmail.com",
},
) -> sib_api_v3_sdk.CreateSmtpEmail:
send_smtp_email = sib_api_v3_sdk.SendSmtpEmail(
to=to, html_content=html_content, sender=sender, subject=subject
to=[to], html_content=html_content, sender=sender, subject=subject
)
return api_instance.send_transac_email(send_smtp_email)
try:
return api_instance.send_transac_email(send_smtp_email)
except ProtocolError:
return api_instance.send_transac_email(send_smtp_email)
58 changes: 33 additions & 25 deletions src/lambda_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,25 @@
)
from src.supabase_client import (
get_training_week_with_coaching,
list_users,
upsert_training_week_update,
upsert_training_week_with_coaching,
)
from src.training_week import generate_training_week
from src.training_week_update import get_updated_training_week
from src.types.mid_week_analysis import MidWeekAnalysis
from src.types.user_row import UserRow


def run_gen_training_week_process(
strava_client: Client, sysmsg_base: str, athlete_id: str
):
def get_athlete_full_name(strava_client: Client) -> str:
athlete = strava_client.get_athlete()
return f"{athlete.firstname} {athlete.lastname}"


def run_gen_training_week_process(user: UserRow) -> None:
sysmsg_base = f"{COACH_ROLE}\nYour client has included the following preferences: {user.preferences}\n"
strava_client = get_strava_client(user.athlete_id)

activities_df = get_activities_df(strava_client)
day_of_week_summaries = get_day_of_week_summaries(activities_df)
weekly_summaries = get_weekly_summaries(activities_df)
Expand All @@ -39,18 +47,21 @@ def run_gen_training_week_process(
)

upsert_training_week_with_coaching(
athlete_id=athlete_id, training_week_with_coaching=training_week_with_coaching
athlete_id=user.athlete_id,
training_week_with_coaching=training_week_with_coaching,
)
send_email(
to={"email": user.email, "name": get_athlete_full_name(strava_client)},
subject="Training Schedule Just Dropped 🏃",
html_content=training_week_to_html(training_week_with_coaching),
)


def run_update_training_week_process(
strava_client: Client, sysmsg_base: str, athlete_id: str
):
training_week_with_coaching = get_training_week_with_coaching(athlete_id)
def run_update_training_week_process(user: UserRow) -> None:
sysmsg_base = f"{COACH_ROLE}\nYour client has included the following preferences: {user.preferences}\n"
strava_client = get_strava_client(user.athlete_id)

training_week_with_coaching = get_training_week_with_coaching(user.athlete_id)
current_weeks_activity_summaries = get_activity_summaries(
strava_client, num_weeks=1
)
Expand All @@ -63,11 +74,12 @@ def run_update_training_week_process(
)

upsert_training_week_update(
athlete_id=athlete_id,
athlete_id=user.athlete_id,
mid_week_analysis=mid_week_analysis,
training_week_update_with_planning=training_week_update_with_planning,
)
send_email(
to={"email": user.email, "name": get_athlete_full_name(strava_client)},
subject="Training Schedule Update 🏃",
html_content=training_week_update_to_html(
mid_week_analysis=mid_week_analysis,
Expand All @@ -77,19 +89,15 @@ def run_update_training_week_process(


def lambda_handler(event, context):
client_preferences = "A) Training for a marathon B) This will be my second marathon C) Prefer workouts on Wednesdays and long runs on Saturdays"
sysmsg_base = f"{COACH_ROLE}\nYour client has included the following preferences: {client_preferences}\n"

# activities setup
athlete_id = os.environ["JAMIES_ATHLETE_ID"]
strava_client = get_strava_client(athlete_id)

# get current time in EST
est = timezone(timedelta(hours=-5))
datetime_now_est = datetime.now(tz=timezone.utc).astimezone(est)

# weekday 6 is Sunday
if datetime_now_est.weekday() == 6:
run_gen_training_week_process(strava_client, sysmsg_base, athlete_id)
else:
run_update_training_week_process(strava_client, sysmsg_base, athlete_id)

for user in list_users():

# get current time in EST
est = timezone(timedelta(hours=-5))
datetime_now_est = datetime.now(tz=timezone.utc).astimezone(est)

# weekday 6 is Sunday
if datetime_now_est.weekday() == 6:
run_gen_training_week_process(user)
else:
run_update_training_week_process(user)
57 changes: 57 additions & 0 deletions src/supabase_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from src.types.mid_week_analysis import MidWeekAnalysis
from src.types.training_week import TrainingWeekWithCoaching, TrainingWeekWithPlanning
from src.types.user_auth_row import UserAuthRow
from src.types.user_row import UserRow

load_dotenv()

Expand Down Expand Up @@ -58,6 +59,30 @@ def get_user_auth(athlete_id: int) -> UserAuthRow:
return UserAuthRow(**response.data[0])


def list_athlete_ids() -> list[int]:
"""
List all athlete_ids in the user_auth table
:return: list of athlete_ids
"""
table = client.table("user_auth")
response = table.select("athlete_id").execute()

return [row["athlete_id"] for row in response.data]


def list_users() -> list[UserRow]:
"""
List all users in the user_auth table
:return: list of UserAuthRow
"""
table = client.table("user")
response = table.select("*").execute()

return [UserRow(**row) for row in response.data]


def upsert_training_week_with_coaching(
athlete_id: int,
training_week_with_coaching: TrainingWeekWithCoaching,
Expand Down Expand Up @@ -146,3 +171,35 @@ def upsert_training_week_update(
response = table.upsert(row_data).execute()

return response


def get_training_week_update(athlete_id: int) -> TrainingWeekWithPlanning:
"""Get the most recent training_week_update row by athlete_id"""

table = client.table("training_week_update")
response = (
table.select("*")
.eq("athlete_id", athlete_id)
.order("created_at", desc=True)
.limit(1)
.execute()
)

try:
response_data = response.data[0]
except Exception:
raise ValueError(
f"Could not find training_week_update row with {athlete_id=}", exc_info=True
)

# clean up the response data
del response_data["id"]
del response_data["athlete_id"]
del response_data["created_at"]
response_data["activities"] = json.loads(response_data["activities"])
response_data["training_week"] = json.loads(response_data["training_week"])
response_data["training_week_update"] = json.loads(
response_data["training_week_update"]
)

return TrainingWeekWithPlanning(**response_data)
2 changes: 1 addition & 1 deletion src/types/training_week.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class TrainingWeekWithPlanning(BaseModel):
description="Draft a plan (used internally) to aid in training week generation. You must adhere to the weekly mileage target and long run range. Do required math (step by step out loud) to plan the week successfully. Distribute volume and intensity evenly throughout the week. If you end up exceeding the weekly mileage target, adjust one of the easy runs to be shorter."
)
training_week: List[TrainingSession] = Field(
description="Unordered collection of training sessions for the week"
description="Unordered collection of REMAINING training sessions for the week"
)


Expand Down
10 changes: 10 additions & 0 deletions src/types/user_row.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from datetime import datetime

from pydantic import BaseModel


class UserRow(BaseModel):
athlete_id: int
email: str
preferences: str
created_at: datetime
17 changes: 4 additions & 13 deletions test.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"cells": [
{
"cell_type": "code",
"execution_count": 3,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -12,7 +12,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -138,18 +138,9 @@
},
{
"cell_type": "code",
"execution_count": 120,
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"athlete_id='98390356' token still valid until 2024-08-21 23:22:07+00:00\n",
"athlete_id='98390356' token still valid until 2024-08-21 23:22:07+00:00\n"
]
}
],
"outputs": [],
"source": [
"from src.lambda_function import lambda_handler\n",
"\n",
Expand Down

0 comments on commit 13c49e3

Please sign in to comment.