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.
Files changed (38) hide show
  1. otf_api/__init__.py +70 -0
  2. otf_api/__version__.py +1 -0
  3. otf_api/api.py +143 -0
  4. otf_api/classes_api.py +44 -0
  5. otf_api/member_api.py +380 -0
  6. otf_api/models/__init__.py +63 -0
  7. otf_api/models/auth.py +141 -0
  8. otf_api/models/base.py +7 -0
  9. otf_api/models/responses/__init__.py +60 -0
  10. otf_api/models/responses/bookings.py +130 -0
  11. otf_api/models/responses/challenge_tracker_content.py +38 -0
  12. otf_api/models/responses/challenge_tracker_detail.py +68 -0
  13. otf_api/models/responses/classes.py +57 -0
  14. otf_api/models/responses/enums.py +87 -0
  15. otf_api/models/responses/favorite_studios.py +106 -0
  16. otf_api/models/responses/latest_agreement.py +21 -0
  17. otf_api/models/responses/member_detail.py +134 -0
  18. otf_api/models/responses/member_membership.py +25 -0
  19. otf_api/models/responses/member_purchases.py +135 -0
  20. otf_api/models/responses/out_of_studio_workout_history.py +41 -0
  21. otf_api/models/responses/performance_summary_detail.py +77 -0
  22. otf_api/models/responses/performance_summary_list.py +67 -0
  23. otf_api/models/responses/studio_detail.py +111 -0
  24. otf_api/models/responses/studio_services.py +57 -0
  25. otf_api/models/responses/telemetry.py +53 -0
  26. otf_api/models/responses/telemetry_hr_history.py +34 -0
  27. otf_api/models/responses/telemetry_max_hr.py +13 -0
  28. otf_api/models/responses/total_classes.py +8 -0
  29. otf_api/models/responses/workouts.py +78 -0
  30. otf_api/performance_api.py +54 -0
  31. otf_api/py.typed +0 -0
  32. otf_api/studios_api.py +96 -0
  33. otf_api/telemetry_api.py +95 -0
  34. otf_api-0.2.0.dist-info/AUTHORS.md +9 -0
  35. otf_api-0.2.0.dist-info/LICENSE +21 -0
  36. otf_api-0.2.0.dist-info/METADATA +28 -0
  37. otf_api-0.2.0.dist-info/RECORD +38 -0
  38. 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,7 @@
1
+ from typing import ClassVar
2
+
3
+ from pydantic import BaseModel, ConfigDict
4
+
5
+
6
+ class OtfBaseModel(BaseModel):
7
+ model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True, extra="forbid")
@@ -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()