otf-api 0.2.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/__init__.py +70 -0
- otf_api/__version__.py +1 -0
- otf_api/api.py +143 -0
- otf_api/classes_api.py +44 -0
- otf_api/member_api.py +380 -0
- otf_api/models/__init__.py +63 -0
- otf_api/models/auth.py +141 -0
- otf_api/models/base.py +7 -0
- otf_api/models/responses/__init__.py +60 -0
- otf_api/models/responses/bookings.py +130 -0
- otf_api/models/responses/challenge_tracker_content.py +38 -0
- otf_api/models/responses/challenge_tracker_detail.py +68 -0
- otf_api/models/responses/classes.py +57 -0
- otf_api/models/responses/enums.py +87 -0
- otf_api/models/responses/favorite_studios.py +106 -0
- otf_api/models/responses/latest_agreement.py +21 -0
- otf_api/models/responses/member_detail.py +134 -0
- otf_api/models/responses/member_membership.py +25 -0
- otf_api/models/responses/member_purchases.py +135 -0
- otf_api/models/responses/out_of_studio_workout_history.py +41 -0
- otf_api/models/responses/performance_summary_detail.py +77 -0
- otf_api/models/responses/performance_summary_list.py +67 -0
- otf_api/models/responses/studio_detail.py +111 -0
- otf_api/models/responses/studio_services.py +57 -0
- otf_api/models/responses/telemetry.py +53 -0
- otf_api/models/responses/telemetry_hr_history.py +34 -0
- otf_api/models/responses/telemetry_max_hr.py +13 -0
- otf_api/models/responses/total_classes.py +8 -0
- otf_api/models/responses/workouts.py +78 -0
- otf_api/performance_api.py +54 -0
- otf_api/py.typed +0 -0
- otf_api/studios_api.py +96 -0
- otf_api/telemetry_api.py +95 -0
- otf_api-0.2.0.dist-info/AUTHORS.md +9 -0
- otf_api-0.2.0.dist-info/LICENSE +21 -0
- otf_api-0.2.0.dist-info/METADATA +28 -0
- otf_api-0.2.0.dist-info/RECORD +38 -0
- otf_api-0.2.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
from .auth import User
|
2
|
+
from .responses import (
|
3
|
+
ALL_CLASS_STATUS,
|
4
|
+
ALL_HISTORY_CLASS_STATUS,
|
5
|
+
ALL_STUDIO_STATUS,
|
6
|
+
BookingList,
|
7
|
+
BookingStatus,
|
8
|
+
ChallengeTrackerContent,
|
9
|
+
ChallengeTrackerDetailList,
|
10
|
+
ChallengeType,
|
11
|
+
EquipmentType,
|
12
|
+
FavoriteStudioList,
|
13
|
+
HistoryClassStatus,
|
14
|
+
LatestAgreement,
|
15
|
+
MemberDetail,
|
16
|
+
MemberMembership,
|
17
|
+
MemberPurchaseList,
|
18
|
+
OtfClassList,
|
19
|
+
OutOfStudioWorkoutHistoryList,
|
20
|
+
PerformanceSummaryDetail,
|
21
|
+
PerformanceSummaryList,
|
22
|
+
StudioDetail,
|
23
|
+
StudioDetailList,
|
24
|
+
StudioServiceList,
|
25
|
+
StudioStatus,
|
26
|
+
Telemetry,
|
27
|
+
TelemetryHrHistory,
|
28
|
+
TelemetryMaxHr,
|
29
|
+
TotalClasses,
|
30
|
+
WorkoutList,
|
31
|
+
)
|
32
|
+
|
33
|
+
__all__ = [
|
34
|
+
"User",
|
35
|
+
"ChallengeType",
|
36
|
+
"BookingStatus",
|
37
|
+
"EquipmentType",
|
38
|
+
"HistoryClassStatus",
|
39
|
+
"StudioStatus",
|
40
|
+
"BookingList",
|
41
|
+
"ChallengeTrackerContent",
|
42
|
+
"ChallengeTrackerDetailList",
|
43
|
+
"LatestAgreement",
|
44
|
+
"MemberDetail",
|
45
|
+
"MemberMembership",
|
46
|
+
"MemberPurchaseList",
|
47
|
+
"OutOfStudioWorkoutHistoryList",
|
48
|
+
"StudioServiceList",
|
49
|
+
"TotalClasses",
|
50
|
+
"WorkoutList",
|
51
|
+
"FavoriteStudioList",
|
52
|
+
"OtfClassList",
|
53
|
+
"TelemetryHrHistory",
|
54
|
+
"Telemetry",
|
55
|
+
"TelemetryMaxHr",
|
56
|
+
"StudioDetail",
|
57
|
+
"StudioDetailList",
|
58
|
+
"ALL_CLASS_STATUS",
|
59
|
+
"ALL_HISTORY_CLASS_STATUS",
|
60
|
+
"ALL_STUDIO_STATUS",
|
61
|
+
"PerformanceSummaryDetail",
|
62
|
+
"PerformanceSummaryList",
|
63
|
+
]
|
otf_api/models/auth.py
ADDED
@@ -0,0 +1,141 @@
|
|
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 OtfBaseModel
|
9
|
+
|
10
|
+
CLIENT_ID = "65knvqta6p37efc2l3eh26pl5o" # from otlive
|
11
|
+
USER_POOL_ID = "us-east-1_dYDxUeyL1"
|
12
|
+
|
13
|
+
|
14
|
+
class IdClaimsData(OtfBaseModel):
|
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
|
+
|
32
|
+
@property
|
33
|
+
def member_uuid(self) -> str:
|
34
|
+
return self.cognito_username
|
35
|
+
|
36
|
+
@property
|
37
|
+
def full_name(self) -> str:
|
38
|
+
return f"{self.given_name} {self.family_name}"
|
39
|
+
|
40
|
+
|
41
|
+
class AccessClaimsData(OtfBaseModel):
|
42
|
+
sub: str
|
43
|
+
device_key: str
|
44
|
+
iss: str
|
45
|
+
client_id: str
|
46
|
+
event_id: str
|
47
|
+
token_use: str
|
48
|
+
scope: str
|
49
|
+
auth_time: int
|
50
|
+
exp: int
|
51
|
+
iat: int
|
52
|
+
jti: str
|
53
|
+
username: str
|
54
|
+
|
55
|
+
@property
|
56
|
+
def member_uuid(self) -> str:
|
57
|
+
return self.username
|
58
|
+
|
59
|
+
|
60
|
+
class User:
|
61
|
+
token_path: ClassVar[Path] = Path("~/.otf/.tokens").expanduser()
|
62
|
+
cognito: Cognito
|
63
|
+
|
64
|
+
def __init__(self, cognito: Cognito):
|
65
|
+
self.cognito = cognito
|
66
|
+
|
67
|
+
@property
|
68
|
+
def member_id(self) -> str:
|
69
|
+
return self.id_claims_data.cognito_username
|
70
|
+
|
71
|
+
@property
|
72
|
+
def member_uuid(self) -> str:
|
73
|
+
return self.access_claims_data.sub
|
74
|
+
|
75
|
+
@property
|
76
|
+
def access_claims_data(self) -> AccessClaimsData:
|
77
|
+
return AccessClaimsData(**self.cognito.access_claims)
|
78
|
+
|
79
|
+
@property
|
80
|
+
def id_claims_data(self) -> IdClaimsData:
|
81
|
+
return IdClaimsData(**self.cognito.id_claims)
|
82
|
+
|
83
|
+
def save_to_disk(self) -> None:
|
84
|
+
self.token_path.parent.mkdir(parents=True, exist_ok=True)
|
85
|
+
data = {
|
86
|
+
"username": self.cognito.username,
|
87
|
+
"id_token": self.cognito.id_token,
|
88
|
+
"access_token": self.cognito.access_token,
|
89
|
+
"refresh_token": self.cognito.refresh_token,
|
90
|
+
}
|
91
|
+
self.token_path.write_text(json.dumps(data))
|
92
|
+
|
93
|
+
@classmethod
|
94
|
+
def load_from_disk(cls, username: str | None = None, password: str | None = None) -> "User":
|
95
|
+
"""Load a User instance from disk. If the token is invalid, reauthenticate with the provided credentials.
|
96
|
+
|
97
|
+
Args:
|
98
|
+
username (str | None): The username to reauthenticate with.
|
99
|
+
password (str | None): The password to reauthenticate with.
|
100
|
+
|
101
|
+
Returns:
|
102
|
+
User: The loaded user.
|
103
|
+
|
104
|
+
Raises:
|
105
|
+
ValueError: If the token is invalid and no username and password are provided.
|
106
|
+
"""
|
107
|
+
attr_dict = json.loads(cls.token_path.read_text())
|
108
|
+
|
109
|
+
cognito_user = Cognito(USER_POOL_ID, CLIENT_ID, **attr_dict)
|
110
|
+
try:
|
111
|
+
cognito_user.verify_tokens()
|
112
|
+
return cls(cognito=cognito_user)
|
113
|
+
except TokenVerificationException:
|
114
|
+
if username and password:
|
115
|
+
user = cls.login(username, password)
|
116
|
+
return user
|
117
|
+
raise
|
118
|
+
|
119
|
+
@classmethod
|
120
|
+
def login(cls, username: str, password: str) -> "User":
|
121
|
+
"""Login and return a User instance. After a successful login, the user is saved to disk.
|
122
|
+
|
123
|
+
Args:
|
124
|
+
username (str): The username to login with.
|
125
|
+
password (str): The password to login with.
|
126
|
+
|
127
|
+
Returns:
|
128
|
+
User: The logged in user.
|
129
|
+
"""
|
130
|
+
cognito_user = Cognito(USER_POOL_ID, CLIENT_ID, username=username)
|
131
|
+
cognito_user.authenticate(password)
|
132
|
+
cognito_user.check_token()
|
133
|
+
user = cls(cognito=cognito_user)
|
134
|
+
user.save_to_disk()
|
135
|
+
return user
|
136
|
+
|
137
|
+
def refresh_token(self) -> "User":
|
138
|
+
"""Refresh the user's access token."""
|
139
|
+
self.cognito.check_token()
|
140
|
+
self.save_to_disk()
|
141
|
+
return self
|
otf_api/models/base.py
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
from .bookings import BookingList
|
2
|
+
from .challenge_tracker_content import ChallengeTrackerContent
|
3
|
+
from .challenge_tracker_detail import ChallengeTrackerDetailList
|
4
|
+
from .classes import OtfClassList
|
5
|
+
from .enums import (
|
6
|
+
ALL_CLASS_STATUS,
|
7
|
+
ALL_HISTORY_CLASS_STATUS,
|
8
|
+
ALL_STUDIO_STATUS,
|
9
|
+
BookingStatus,
|
10
|
+
ChallengeType,
|
11
|
+
EquipmentType,
|
12
|
+
HistoryClassStatus,
|
13
|
+
StudioStatus,
|
14
|
+
)
|
15
|
+
from .favorite_studios import FavoriteStudioList
|
16
|
+
from .latest_agreement import LatestAgreement
|
17
|
+
from .member_detail import MemberDetail
|
18
|
+
from .member_membership import MemberMembership
|
19
|
+
from .member_purchases import MemberPurchaseList
|
20
|
+
from .out_of_studio_workout_history import OutOfStudioWorkoutHistoryList
|
21
|
+
from .performance_summary_detail import PerformanceSummaryDetail
|
22
|
+
from .performance_summary_list import PerformanceSummaryList
|
23
|
+
from .studio_detail import StudioDetail, StudioDetailList
|
24
|
+
from .studio_services import StudioServiceList
|
25
|
+
from .telemetry import Telemetry
|
26
|
+
from .telemetry_hr_history import TelemetryHrHistory
|
27
|
+
from .telemetry_max_hr import TelemetryMaxHr
|
28
|
+
from .total_classes import TotalClasses
|
29
|
+
from .workouts import WorkoutList
|
30
|
+
|
31
|
+
__all__ = [
|
32
|
+
"BookingList",
|
33
|
+
"ChallengeTrackerContent",
|
34
|
+
"ChallengeTrackerDetailList",
|
35
|
+
"LatestAgreement",
|
36
|
+
"MemberDetail",
|
37
|
+
"MemberMembership",
|
38
|
+
"MemberPurchaseList",
|
39
|
+
"OutOfStudioWorkoutHistoryList",
|
40
|
+
"StudioServiceList",
|
41
|
+
"TotalClasses",
|
42
|
+
"WorkoutList",
|
43
|
+
"ChallengeType",
|
44
|
+
"BookingStatus",
|
45
|
+
"EquipmentType",
|
46
|
+
"HistoryClassStatus",
|
47
|
+
"StudioStatus",
|
48
|
+
"FavoriteStudioList",
|
49
|
+
"OtfClassList",
|
50
|
+
"TelemetryHrHistory",
|
51
|
+
"Telemetry",
|
52
|
+
"TelemetryMaxHr",
|
53
|
+
"StudioDetail",
|
54
|
+
"StudioDetailList",
|
55
|
+
"ALL_CLASS_STATUS",
|
56
|
+
"ALL_HISTORY_CLASS_STATUS",
|
57
|
+
"ALL_STUDIO_STATUS",
|
58
|
+
"PerformanceSummaryDetail",
|
59
|
+
"PerformanceSummaryList",
|
60
|
+
]
|
@@ -0,0 +1,130 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
3
|
+
from pydantic import Field
|
4
|
+
|
5
|
+
from otf_api.models.base import OtfBaseModel
|
6
|
+
|
7
|
+
from .enums import BookingStatus, StudioStatus
|
8
|
+
|
9
|
+
|
10
|
+
class Location(OtfBaseModel):
|
11
|
+
address_one: str = Field(alias="address1")
|
12
|
+
address_two: str | None = Field(alias="address2")
|
13
|
+
city: str
|
14
|
+
country: str | None = None
|
15
|
+
distance: float | None = None
|
16
|
+
latitude: float = Field(alias="latitude")
|
17
|
+
location_name: str | None = Field(None, alias="locationName")
|
18
|
+
longitude: float = Field(alias="longitude")
|
19
|
+
phone_number: str = Field(alias="phone")
|
20
|
+
postal_code: str | None = Field(None, alias="postalCode")
|
21
|
+
state: str | None = None
|
22
|
+
|
23
|
+
|
24
|
+
class Coach(OtfBaseModel):
|
25
|
+
coach_uuid: str = Field(alias="coachUUId")
|
26
|
+
name: str
|
27
|
+
first_name: str = Field(alias="firstName")
|
28
|
+
last_name: str = Field(alias="lastName")
|
29
|
+
image_url: str = Field(alias="imageUrl")
|
30
|
+
profile_picture_url: str | None = Field(None, alias="profilePictureUrl")
|
31
|
+
|
32
|
+
|
33
|
+
class Currency(OtfBaseModel):
|
34
|
+
currency_alphabetic_code: str = Field(alias="currencyAlphabeticCode")
|
35
|
+
|
36
|
+
|
37
|
+
class DefaultCurrency(OtfBaseModel):
|
38
|
+
currency_id: int = Field(alias="currencyId")
|
39
|
+
currency: Currency
|
40
|
+
|
41
|
+
|
42
|
+
class StudioLocationCountry(OtfBaseModel):
|
43
|
+
country_currency_code: str = Field(alias="countryCurrencyCode")
|
44
|
+
default_currency: DefaultCurrency = Field(alias="defaultCurrency")
|
45
|
+
|
46
|
+
|
47
|
+
class StudioLocation(OtfBaseModel):
|
48
|
+
latitude: float = Field(alias="latitude")
|
49
|
+
longitude: float = Field(alias="longitude")
|
50
|
+
phone_number: str = Field(alias="phoneNumber")
|
51
|
+
physical_city: str = Field(alias="physicalCity")
|
52
|
+
physical_address: str = Field(alias="physicalAddress")
|
53
|
+
physical_address2: str | None = Field(alias="physicalAddress2")
|
54
|
+
physical_state: str = Field(alias="physicalState")
|
55
|
+
physical_postal_code: str = Field(alias="physicalPostalCode")
|
56
|
+
physical_region: str = Field(alias="physicalRegion")
|
57
|
+
physical_country_id: int = Field(alias="physicalCountryId")
|
58
|
+
physical_country: str = Field(alias="physicalCountry")
|
59
|
+
country: StudioLocationCountry = Field(alias="country")
|
60
|
+
|
61
|
+
|
62
|
+
class Studio(OtfBaseModel):
|
63
|
+
studio_uuid: str = Field(alias="studioUUId")
|
64
|
+
studio_name: str = Field(alias="studioName")
|
65
|
+
description: str
|
66
|
+
contact_email: str = Field(alias="contactEmail")
|
67
|
+
status: StudioStatus
|
68
|
+
logo_url: str | None = Field(alias="logoUrl")
|
69
|
+
time_zone: str = Field(alias="timeZone")
|
70
|
+
mbo_studio_id: int = Field(alias="mboStudioId")
|
71
|
+
studio_id: int = Field(alias="studioId")
|
72
|
+
allows_cr_waitlist: bool | None = Field(None, alias="allowsCRWaitlist")
|
73
|
+
cr_waitlist_flag_last_updated: datetime = Field(alias="crWaitlistFlagLastUpdated")
|
74
|
+
studio_location: StudioLocation = Field(alias="studioLocation")
|
75
|
+
|
76
|
+
|
77
|
+
class OtfClass(OtfBaseModel):
|
78
|
+
class_uuid: str = Field(alias="classUUId")
|
79
|
+
name: str
|
80
|
+
description: str
|
81
|
+
start_date_time: datetime = Field(alias="startDateTime")
|
82
|
+
end_date_time: datetime = Field(alias="endDateTime")
|
83
|
+
is_available: bool = Field(alias="isAvailable")
|
84
|
+
is_cancelled: bool = Field(alias="isCancelled")
|
85
|
+
program_name: str = Field(alias="programName")
|
86
|
+
coach_id: int = Field(alias="coachId")
|
87
|
+
studio: Studio
|
88
|
+
coach: Coach
|
89
|
+
location: Location
|
90
|
+
virtual_class: bool | None = Field(None, alias="virtualClass")
|
91
|
+
|
92
|
+
|
93
|
+
class Member(OtfBaseModel):
|
94
|
+
member_uuid: str = Field(alias="memberUUId")
|
95
|
+
first_name: str = Field(alias="firstName")
|
96
|
+
last_name: str = Field(alias="lastName")
|
97
|
+
email: str
|
98
|
+
phone_number: str = Field(alias="phoneNumber")
|
99
|
+
gender: str
|
100
|
+
cc_last_4: str = Field(alias="ccLast4")
|
101
|
+
|
102
|
+
|
103
|
+
class Booking(OtfBaseModel):
|
104
|
+
class_booking_id: int = Field(alias="classBookingId")
|
105
|
+
class_booking_uuid: str = Field(alias="classBookingUUId")
|
106
|
+
studio_id: int = Field(alias="studioId")
|
107
|
+
class_id: int = Field(alias="classId")
|
108
|
+
is_intro: bool = Field(alias="isIntro")
|
109
|
+
member_id: int = Field(alias="memberId")
|
110
|
+
mbo_member_id: str = Field(alias="mboMemberId")
|
111
|
+
mbo_class_id: int = Field(alias="mboClassId")
|
112
|
+
mbo_visit_id: int | None = Field(None, alias="mboVisitId")
|
113
|
+
mbo_waitlist_entry_id: int | None = Field(alias="mboWaitlistEntryId")
|
114
|
+
mbo_sync_message: str | None = Field(alias="mboSyncMessage")
|
115
|
+
status: BookingStatus
|
116
|
+
booked_date: datetime | None = Field(None, alias="bookedDate")
|
117
|
+
checked_in_date: datetime | None = Field(alias="checkedInDate")
|
118
|
+
cancelled_date: datetime | None = Field(alias="cancelledDate")
|
119
|
+
created_by: str = Field(alias="createdBy")
|
120
|
+
created_date: datetime = Field(alias="createdDate")
|
121
|
+
updated_by: str = Field(alias="updatedBy")
|
122
|
+
updated_date: datetime = Field(alias="updatedDate")
|
123
|
+
is_deleted: bool = Field(alias="isDeleted")
|
124
|
+
member: Member
|
125
|
+
waitlist_position: int | None = Field(None, alias="waitlistPosition")
|
126
|
+
class_: OtfClass | None = Field(None, alias="class")
|
127
|
+
|
128
|
+
|
129
|
+
class BookingList(OtfBaseModel):
|
130
|
+
bookings: list[Booking]
|
@@ -0,0 +1,38 @@
|
|
1
|
+
from pydantic import Field
|
2
|
+
|
3
|
+
from otf_api.models.base import OtfBaseModel
|
4
|
+
|
5
|
+
|
6
|
+
class Year(OtfBaseModel):
|
7
|
+
year: str = Field(..., alias="Year")
|
8
|
+
is_participated: bool = Field(..., alias="IsParticipated")
|
9
|
+
in_progress: bool = Field(..., alias="InProgress")
|
10
|
+
|
11
|
+
|
12
|
+
class Program(OtfBaseModel):
|
13
|
+
challenge_category_id: int = Field(..., alias="ChallengeCategoryId")
|
14
|
+
challenge_sub_category_id: int = Field(..., alias="ChallengeSubCategoryId")
|
15
|
+
challenge_name: str = Field(..., alias="ChallengeName")
|
16
|
+
years: list[Year] = Field(..., alias="Years")
|
17
|
+
logo_url: str = Field(..., alias="LogoUrl")
|
18
|
+
|
19
|
+
|
20
|
+
class Challenge(OtfBaseModel):
|
21
|
+
challenge_category_id: int = Field(..., alias="ChallengeCategoryId")
|
22
|
+
challenge_sub_category_id: int = Field(..., alias="ChallengeSubCategoryId")
|
23
|
+
challenge_name: str = Field(..., alias="ChallengeName")
|
24
|
+
years: list[Year] = Field(..., alias="Years")
|
25
|
+
logo_url: str = Field(..., alias="LogoUrl")
|
26
|
+
|
27
|
+
|
28
|
+
class Benchmark(OtfBaseModel):
|
29
|
+
equipment_id: int = Field(..., alias="EquipmentId")
|
30
|
+
equipment_name: str = Field(..., alias="EquipmentName")
|
31
|
+
years: list[Year] = Field(..., alias="Years")
|
32
|
+
logo_url: str = Field(..., alias="LogoUrl")
|
33
|
+
|
34
|
+
|
35
|
+
class ChallengeTrackerContent(OtfBaseModel):
|
36
|
+
programs: list[Program] = Field(..., alias="Programs")
|
37
|
+
challenges: list[Challenge] = Field(..., alias="Challenges")
|
38
|
+
benchmarks: list[Benchmark] = Field(..., alias="Benchmarks")
|
@@ -0,0 +1,68 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import Any
|
3
|
+
|
4
|
+
from pydantic import Field
|
5
|
+
|
6
|
+
from otf_api.models.base import OtfBaseModel
|
7
|
+
|
8
|
+
|
9
|
+
class MetricEntry(OtfBaseModel):
|
10
|
+
title: str = Field(..., alias="Title")
|
11
|
+
equipment_id: int = Field(..., alias="EquipmentId")
|
12
|
+
entry_type: str = Field(..., alias="EntryType")
|
13
|
+
metric_key: str = Field(..., alias="MetricKey")
|
14
|
+
min_value: str = Field(..., alias="MinValue")
|
15
|
+
max_value: str = Field(..., alias="MaxValue")
|
16
|
+
|
17
|
+
|
18
|
+
class BenchmarkHistory(OtfBaseModel):
|
19
|
+
studio_name: str = Field(..., alias="StudioName")
|
20
|
+
equipment_id: int = Field(..., alias="EquipmentId")
|
21
|
+
result: float | str = Field(..., alias="Result")
|
22
|
+
date_created: datetime = Field(..., alias="DateCreated")
|
23
|
+
date_updated: datetime = Field(..., alias="DateUpdated")
|
24
|
+
class_time: datetime = Field(..., alias="ClassTime")
|
25
|
+
challenge_sub_category_id: None = Field(..., alias="ChallengeSubCategoryId")
|
26
|
+
class_id: int = Field(..., alias="ClassId")
|
27
|
+
substitute_id: int | None = Field(..., alias="SubstituteId")
|
28
|
+
weight_lbs: int = Field(..., alias="WeightLBS")
|
29
|
+
class_name: str = Field(..., alias="ClassName")
|
30
|
+
coach_name: str = Field(..., alias="CoachName")
|
31
|
+
coach_image_url: str = Field(..., alias="CoachImageUrl")
|
32
|
+
workout_type_id: None = Field(..., alias="WorkoutTypeId")
|
33
|
+
workout_id: None = Field(..., alias="WorkoutId")
|
34
|
+
linked_challenges: list[Any] = Field(
|
35
|
+
..., alias="LinkedChallenges"
|
36
|
+
) # not sure what this will be, never seen it before
|
37
|
+
|
38
|
+
|
39
|
+
class ChallengeHistory(OtfBaseModel):
|
40
|
+
challenge_objective: str = Field(..., alias="ChallengeObjective")
|
41
|
+
challenge_id: int = Field(..., alias="ChallengeId")
|
42
|
+
studio_id: int = Field(..., alias="StudioId")
|
43
|
+
studio_name: str = Field(..., alias="StudioName")
|
44
|
+
start_date: datetime = Field(..., alias="StartDate")
|
45
|
+
end_date: datetime = Field(..., alias="EndDate")
|
46
|
+
total_result: float | str = Field(..., alias="TotalResult")
|
47
|
+
is_finished: bool = Field(..., alias="IsFinished")
|
48
|
+
benchmark_histories: list[BenchmarkHistory] = Field(..., alias="BenchmarkHistories")
|
49
|
+
|
50
|
+
|
51
|
+
class ChallengeTrackerDetail(OtfBaseModel):
|
52
|
+
challenge_category_id: int = Field(..., alias="ChallengeCategoryId")
|
53
|
+
challenge_sub_category_id: None = Field(..., alias="ChallengeSubCategoryId")
|
54
|
+
equipment_id: int = Field(..., alias="EquipmentId")
|
55
|
+
equipment_name: str = Field(..., alias="EquipmentName")
|
56
|
+
metric_entry: MetricEntry = Field(..., alias="MetricEntry")
|
57
|
+
challenge_name: str = Field(..., alias="ChallengeName")
|
58
|
+
logo_url: str = Field(..., alias="LogoUrl")
|
59
|
+
best_record: float | str = Field(..., alias="BestRecord")
|
60
|
+
last_record: float | str = Field(..., alias="LastRecord")
|
61
|
+
previous_record: float | str = Field(..., alias="PreviousRecord")
|
62
|
+
unit: str | None = Field(..., alias="Unit")
|
63
|
+
goals: None = Field(..., alias="Goals")
|
64
|
+
challenge_histories: list[ChallengeHistory] = Field(..., alias="ChallengeHistories")
|
65
|
+
|
66
|
+
|
67
|
+
class ChallengeTrackerDetailList(OtfBaseModel):
|
68
|
+
details: list[ChallengeTrackerDetail]
|
@@ -0,0 +1,57 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
3
|
+
from otf_api.models.base import OtfBaseModel
|
4
|
+
|
5
|
+
|
6
|
+
class Address(OtfBaseModel):
|
7
|
+
line1: str
|
8
|
+
city: str
|
9
|
+
state: str
|
10
|
+
country: str
|
11
|
+
postal_code: str
|
12
|
+
|
13
|
+
|
14
|
+
class Studio(OtfBaseModel):
|
15
|
+
id: str
|
16
|
+
name: str
|
17
|
+
mbo_studio_id: str
|
18
|
+
time_zone: str
|
19
|
+
currency_code: str
|
20
|
+
address: Address
|
21
|
+
phone_number: str
|
22
|
+
latitude: float
|
23
|
+
longitude: float
|
24
|
+
|
25
|
+
|
26
|
+
class Coach(OtfBaseModel):
|
27
|
+
mbo_staff_id: str
|
28
|
+
first_name: str
|
29
|
+
image_url: str | None = None
|
30
|
+
|
31
|
+
|
32
|
+
class OtfClass(OtfBaseModel):
|
33
|
+
id: str
|
34
|
+
ot_base_class_uuid: str
|
35
|
+
starts_at: datetime
|
36
|
+
starts_at_local: datetime
|
37
|
+
ends_at: datetime
|
38
|
+
ends_at_local: datetime
|
39
|
+
name: str
|
40
|
+
type: str
|
41
|
+
studio: Studio
|
42
|
+
coach: Coach
|
43
|
+
max_capacity: int
|
44
|
+
booking_capacity: int
|
45
|
+
waitlist_size: int
|
46
|
+
full: bool
|
47
|
+
waitlist_available: bool
|
48
|
+
canceled: bool
|
49
|
+
mbo_class_id: str
|
50
|
+
mbo_class_schedule_id: str
|
51
|
+
mbo_class_description_id: str
|
52
|
+
created_at: datetime
|
53
|
+
updated_at: datetime
|
54
|
+
|
55
|
+
|
56
|
+
class OtfClassList(OtfBaseModel):
|
57
|
+
classes: list[OtfClass]
|
@@ -0,0 +1,87 @@
|
|
1
|
+
from enum import Enum
|
2
|
+
|
3
|
+
|
4
|
+
class StudioStatus(str, Enum):
|
5
|
+
OTHER = "OTHER"
|
6
|
+
ACTIVE = "Active"
|
7
|
+
INACTIVE = "Inactive"
|
8
|
+
COMING_SOON = "Coming Soon"
|
9
|
+
TEMP_CLOSED = "Temporarily Closed"
|
10
|
+
PERM_CLOSED = "Permanently Closed"
|
11
|
+
|
12
|
+
@classmethod
|
13
|
+
def all_statuses(cls) -> list[str]:
|
14
|
+
return list(cls.__members__.values())
|
15
|
+
|
16
|
+
|
17
|
+
class EquipmentType(int, Enum):
|
18
|
+
Treadmill = 2
|
19
|
+
Strider = 3
|
20
|
+
Rower = 4
|
21
|
+
Bike = 5
|
22
|
+
WeightFloor = 6
|
23
|
+
PowerWalker = 7
|
24
|
+
|
25
|
+
|
26
|
+
class ChallengeType(int, Enum):
|
27
|
+
Other = 0
|
28
|
+
DriTri = 2
|
29
|
+
MarathonMonth = 5
|
30
|
+
HellWeek = 52
|
31
|
+
Mayhem = 58
|
32
|
+
TwelveDaysOfFitness = 63
|
33
|
+
Transformation = 64
|
34
|
+
RemixInSix = 65
|
35
|
+
Push = 66
|
36
|
+
BackAtIt = 84
|
37
|
+
|
38
|
+
|
39
|
+
class BookingStatus(str, Enum):
|
40
|
+
CheckedIn = "Checked In"
|
41
|
+
CancelCheckinPending = "Cancel Checkin Pending"
|
42
|
+
CancelCheckinRequested = "Cancel Checkin Requested"
|
43
|
+
Cancelled = "Cancelled"
|
44
|
+
LateCancelled = "Late Cancelled"
|
45
|
+
Booked = "Booked"
|
46
|
+
Waitlisted = "Waitlisted"
|
47
|
+
CheckinPending = "Checkin Pending"
|
48
|
+
CheckinRequested = "Checkin Requested"
|
49
|
+
CheckinCancelled = "Checkin Cancelled"
|
50
|
+
|
51
|
+
@classmethod
|
52
|
+
def all_statuses(cls) -> list[str]:
|
53
|
+
return list(cls.__members__.values())
|
54
|
+
|
55
|
+
|
56
|
+
class HistoryBookingStatus(str, Enum):
|
57
|
+
Attended = "Attended"
|
58
|
+
Cancelled = "Cancelled"
|
59
|
+
LateCancelled = "Late Cancelled"
|
60
|
+
|
61
|
+
@classmethod
|
62
|
+
def all_statuses(cls) -> list[str]:
|
63
|
+
return list(cls.__members__.values())
|
64
|
+
|
65
|
+
|
66
|
+
class HistoryClassStatus(str, Enum):
|
67
|
+
CheckedIn = "Checked In"
|
68
|
+
CancelCheckinPending = "Cancel Checkin Pending"
|
69
|
+
CancelCheckinRequested = "Cancel Checkin Requested"
|
70
|
+
LateCancelled = "Late Cancelled"
|
71
|
+
Booked = "Booked"
|
72
|
+
Waitlisted = "Waitlisted"
|
73
|
+
CheckinPending = "Checkin Pending"
|
74
|
+
CheckinRequested = "Checkin Requested"
|
75
|
+
CheckinCancelled = "Checkin Cancelled"
|
76
|
+
Pending = "Pending"
|
77
|
+
Confirmed = "Confirmed"
|
78
|
+
Requested = "Requested"
|
79
|
+
|
80
|
+
@classmethod
|
81
|
+
def all_statuses(cls) -> list[str]:
|
82
|
+
return list(cls.__members__.values())
|
83
|
+
|
84
|
+
|
85
|
+
ALL_CLASS_STATUS = BookingStatus.all_statuses()
|
86
|
+
ALL_HISTORY_CLASS_STATUS = HistoryClassStatus.all_statuses()
|
87
|
+
ALL_STUDIO_STATUS = StudioStatus.all_statuses()
|