otf-api 0.3.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
otf_api/models/auth.py DELETED
@@ -1,147 +0,0 @@
1
- import json
2
- from pathlib import Path
3
- from typing import ClassVar
4
-
5
- from pycognito import Cognito, TokenVerificationException
6
- from pydantic import Field
7
-
8
- from otf_api.models.base import OtfItemBase
9
-
10
- CLIENT_ID = "65knvqta6p37efc2l3eh26pl5o" # from otlive
11
- USER_POOL_ID = "us-east-1_dYDxUeyL1"
12
-
13
-
14
- class IdClaimsData(OtfItemBase):
15
- sub: str
16
- email_verified: bool
17
- iss: str
18
- cognito_username: str = Field(alias="cognito:username")
19
- given_name: str
20
- locale: str
21
- home_studio_id: str = Field(alias="custom:home_studio_id")
22
- aud: str
23
- event_id: str
24
- token_use: str
25
- auth_time: int
26
- exp: int
27
- is_migration: str = Field(alias="custom:isMigration")
28
- iat: int
29
- family_name: str
30
- email: str
31
- koji_person_id: str = Field(alias="custom:koji_person_id")
32
-
33
- @property
34
- def member_uuid(self) -> str:
35
- return self.cognito_username
36
-
37
- @property
38
- def full_name(self) -> str:
39
- return f"{self.given_name} {self.family_name}"
40
-
41
-
42
- class AccessClaimsData(OtfItemBase):
43
- sub: str
44
- device_key: str
45
- iss: str
46
- client_id: str
47
- event_id: str
48
- token_use: str
49
- scope: str
50
- auth_time: int
51
- exp: int
52
- iat: int
53
- jti: str
54
- username: str
55
-
56
- @property
57
- def member_uuid(self) -> str:
58
- return self.username
59
-
60
-
61
- class User:
62
- token_path: ClassVar[Path] = Path("~/.otf/.tokens").expanduser()
63
- cognito: Cognito
64
-
65
- def __init__(self, cognito: Cognito):
66
- self.cognito = cognito
67
-
68
- @property
69
- def member_id(self) -> str:
70
- return self.id_claims_data.cognito_username
71
-
72
- @property
73
- def member_uuid(self) -> str:
74
- return self.access_claims_data.sub
75
-
76
- @property
77
- def access_claims_data(self) -> AccessClaimsData:
78
- return AccessClaimsData(**self.cognito.access_claims)
79
-
80
- @property
81
- def id_claims_data(self) -> IdClaimsData:
82
- return IdClaimsData(**self.cognito.id_claims)
83
-
84
- def save_to_disk(self) -> None:
85
- self.token_path.parent.mkdir(parents=True, exist_ok=True)
86
- data = {
87
- "username": self.cognito.username,
88
- "id_token": self.cognito.id_token,
89
- "access_token": self.cognito.access_token,
90
- "refresh_token": self.cognito.refresh_token,
91
- }
92
- self.token_path.write_text(json.dumps(data))
93
-
94
- @classmethod
95
- def cache_file_exists(cls) -> bool:
96
- return cls.token_path.exists()
97
-
98
- @classmethod
99
- def username_from_disk(cls) -> str:
100
- val: str = json.loads(cls.token_path.read_text())["username"]
101
- return val
102
-
103
- @classmethod
104
- def load_from_disk(cls, username: str, password: str) -> "User":
105
- """Load a User instance from disk. If the token is invalid, reauthenticate with the provided credentials.
106
-
107
- Args:
108
- username (str): The username to reauthenticate with.
109
- password (str): The password to reauthenticate with.
110
-
111
- Returns:
112
- User: The loaded user.
113
-
114
- """
115
- attr_dict = json.loads(cls.token_path.read_text())
116
-
117
- cognito_user = Cognito(USER_POOL_ID, CLIENT_ID, **attr_dict)
118
- try:
119
- cognito_user.verify_tokens()
120
- return cls(cognito=cognito_user)
121
- except TokenVerificationException:
122
- user = cls.login(username, password)
123
- return user
124
-
125
- @classmethod
126
- def login(cls, username: str, password: str) -> "User":
127
- """Login and return a User instance. After a successful login, the user is saved to disk.
128
-
129
- Args:
130
- username (str): The username to login with.
131
- password (str): The password to login with.
132
-
133
- Returns:
134
- User: The logged in user.
135
- """
136
- cognito_user = Cognito(USER_POOL_ID, CLIENT_ID, username=username)
137
- cognito_user.authenticate(password)
138
- cognito_user.check_token()
139
- user = cls(cognito=cognito_user)
140
- user.save_to_disk()
141
- return user
142
-
143
- def refresh_token(self) -> "User":
144
- """Refresh the user's access token."""
145
- self.cognito.check_token()
146
- self.save_to_disk()
147
- return self
@@ -1,78 +0,0 @@
1
- from ast import literal_eval
2
- from datetime import datetime
3
- from typing import Any
4
-
5
- from pydantic import Field, PrivateAttr
6
-
7
- from otf_api.models.base import OtfItemBase
8
-
9
-
10
- class WorkoutType(OtfItemBase):
11
- id: int
12
- display_name: str = Field(..., alias="displayName")
13
- icon: str
14
-
15
-
16
- class Workout(OtfItemBase):
17
- studio_number: str = Field(..., alias="studioNumber")
18
- studio_name: str = Field(..., alias="studioName")
19
- class_type: str = Field(..., alias="classType")
20
- active_time: int = Field(..., alias="activeTime")
21
- coach: str
22
- member_uuid: str = Field(..., alias="memberUuId")
23
- class_date: datetime = Field(..., alias="classDate")
24
- total_calories: int = Field(..., alias="totalCalories")
25
- avg_hr: int = Field(..., alias="avgHr")
26
- max_hr: int = Field(..., alias="maxHr")
27
- avg_percent_hr: int = Field(..., alias="avgPercentHr")
28
- max_percent_hr: int = Field(..., alias="maxPercentHr")
29
- total_splat_points: int = Field(..., alias="totalSplatPoints")
30
- red_zone_time_second: int = Field(..., alias="redZoneTimeSecond")
31
- orange_zone_time_second: int = Field(..., alias="orangeZoneTimeSecond")
32
- green_zone_time_second: int = Field(..., alias="greenZoneTimeSecond")
33
- blue_zone_time_second: int = Field(..., alias="blueZoneTimeSecond")
34
- black_zone_time_second: int = Field(..., alias="blackZoneTimeSecond")
35
- step_count: int = Field(..., alias="stepCount")
36
- class_history_uuid: str = Field(..., alias="classHistoryUuId")
37
- class_id: str = Field(..., alias="classId")
38
- date_created: datetime = Field(..., alias="dateCreated")
39
- date_updated: datetime = Field(..., alias="dateUpdated")
40
- is_intro: bool = Field(..., alias="isIntro")
41
- is_leader: bool = Field(..., alias="isLeader")
42
- member_email: None = Field(..., alias="memberEmail")
43
- member_name: str = Field(..., alias="memberName")
44
- member_performance_id: str = Field(..., alias="memberPerformanceId")
45
- minute_by_minute_hr: list[int] = Field(
46
- ...,
47
- alias="minuteByMinuteHr",
48
- description="HR data for each minute of the workout. It is returned as a string literal, so it needs to be "
49
- "evaluated to a list. If can't be parsed, it will return an empty list.",
50
- )
51
- source: str
52
- studio_account_uuid: str = Field(..., alias="studioAccountUuId")
53
- version: str
54
- workout_type: WorkoutType = Field(..., alias="workoutType")
55
- _minute_by_minute_raw: str | None = PrivateAttr(None)
56
-
57
- @property
58
- def active_time_minutes(self) -> int:
59
- """Get the active time in minutes."""
60
- return self.active_time // 60
61
-
62
- def __init__(self, **data: Any):
63
- if "minuteByMinuteHr" in data:
64
- try:
65
- data["minuteByMinuteHr"] = literal_eval(data["minuteByMinuteHr"])
66
- except (ValueError, SyntaxError):
67
- data["minuteByMinuteHr"] = []
68
-
69
- super().__init__(**data)
70
- self._minute_by_minute_raw = data.get("minuteByMinuteHr")
71
-
72
-
73
- class WorkoutList(OtfItemBase):
74
- workouts: list[Workout]
75
-
76
- @property
77
- def by_class_history_uuid(self) -> dict[str, Workout]:
78
- return {workout.class_history_uuid: workout for workout in self.workouts}