otf-api 0.8.2__py3-none-any.whl → 0.9.1__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 (43) hide show
  1. otf_api/__init__.py +7 -4
  2. otf_api/api.py +699 -480
  3. otf_api/auth/__init__.py +4 -0
  4. otf_api/auth/auth.py +234 -0
  5. otf_api/auth/user.py +66 -0
  6. otf_api/auth/utils.py +129 -0
  7. otf_api/exceptions.py +38 -5
  8. otf_api/filters.py +97 -0
  9. otf_api/logging.py +19 -0
  10. otf_api/models/__init__.py +27 -38
  11. otf_api/models/body_composition_list.py +47 -50
  12. otf_api/models/bookings.py +63 -87
  13. otf_api/models/challenge_tracker_content.py +42 -21
  14. otf_api/models/challenge_tracker_detail.py +68 -48
  15. otf_api/models/classes.py +53 -62
  16. otf_api/models/enums.py +108 -30
  17. otf_api/models/lifetime_stats.py +59 -45
  18. otf_api/models/member_detail.py +95 -115
  19. otf_api/models/member_membership.py +18 -17
  20. otf_api/models/member_purchases.py +21 -127
  21. otf_api/models/mixins.py +37 -33
  22. otf_api/models/notifications.py +17 -0
  23. otf_api/models/out_of_studio_workout_history.py +22 -31
  24. otf_api/models/performance_summary_detail.py +47 -42
  25. otf_api/models/performance_summary_list.py +19 -37
  26. otf_api/models/studio_detail.py +51 -98
  27. otf_api/models/studio_services.py +27 -48
  28. otf_api/models/telemetry.py +14 -5
  29. otf_api/utils.py +134 -0
  30. {otf_api-0.8.2.dist-info → otf_api-0.9.1.dist-info}/METADATA +21 -10
  31. otf_api-0.9.1.dist-info/RECORD +35 -0
  32. {otf_api-0.8.2.dist-info → otf_api-0.9.1.dist-info}/WHEEL +1 -1
  33. otf_api/auth.py +0 -316
  34. otf_api/models/book_class.py +0 -89
  35. otf_api/models/cancel_booking.py +0 -49
  36. otf_api/models/favorite_studios.py +0 -106
  37. otf_api/models/latest_agreement.py +0 -21
  38. otf_api/models/telemetry_hr_history.py +0 -34
  39. otf_api/models/telemetry_max_hr.py +0 -13
  40. otf_api/models/total_classes.py +0 -8
  41. otf_api-0.8.2.dist-info/AUTHORS.md +0 -9
  42. otf_api-0.8.2.dist-info/RECORD +0 -36
  43. {otf_api-0.8.2.dist-info → otf_api-0.9.1.dist-info}/LICENSE +0 -0
@@ -0,0 +1,35 @@
1
+ otf_api/__init__.py,sha256=dGgyclSo165V_hZAl7Z5E06WQrs5NjO6fXtPcbo3RIg,204
2
+ otf_api/api.py,sha256=Ah6bheezsV-RLxPLGKZqqW77gotWkznLYmEeRhEwJaY,47006
3
+ otf_api/auth/__init__.py,sha256=Pu6ugbEXhgjJEpYKr7K2CqEac53Wq9FRF3F16GLQ_ww,133
4
+ otf_api/auth/auth.py,sha256=m9qzUn0hdAo6AZHm2Mn054nLqUWPxEyP3y3DOBVkvYA,9010
5
+ otf_api/auth/user.py,sha256=HgggfneeVMnKFWSUMnlikfZyC__HE8vVaKSpBS4_sIg,2256
6
+ otf_api/auth/utils.py,sha256=jUH_A1-DU3KfY-XrymCuQoud79o9qfu5P9Ws9QA2aWs,3211
7
+ otf_api/exceptions.py,sha256=mt0k0-2oNcpNhboYzkywpt535W6bHjx6gro7P3PpYzo,1463
8
+ otf_api/filters.py,sha256=fk2bFGi3srjS96qZlaDx-ARZRaj93NUTUdMJ01TX420,3702
9
+ otf_api/logging.py,sha256=PRZpCaJ1F1Xya3L9Efkt3mKS5_QNr3sXjEUERSxYjvE,563
10
+ otf_api/models/__init__.py,sha256=czt_OYsU4igeudRAi8kqOQro6fjNrbE9aLr--FA76Sg,1588
11
+ otf_api/models/base.py,sha256=KJlIxl_sRj6f-g5vKYPw4yV6fGDk-fwZ93EO0JGPYMw,202
12
+ otf_api/models/body_composition_list.py,sha256=jGdR-9ScvIOtULJNB99aYh2INk2ihoHAnTWtbQCIea4,12202
13
+ otf_api/models/bookings.py,sha256=8zgLnQ40ci0c7AimGeoAI-Raw8d2byvKoXkJXyW1xUE,4260
14
+ otf_api/models/challenge_tracker_content.py,sha256=zukbda38DloiBHW9HUEKQnumGhgVqpjjbxo7G4bDIc0,2630
15
+ otf_api/models/challenge_tracker_detail.py,sha256=KDfLRDjr8quVhDPVj9x_tuLnkJPua5y8C3WtGIVzXZw,4356
16
+ otf_api/models/classes.py,sha256=DZ7oo_MNK7m3ul2gK929maGBksekG9RtLzYa-Di8skk,3005
17
+ otf_api/models/enums.py,sha256=qXpnJwUyR5fZxr_z1VIlgo_uOGFdGNqoaITVpiA2z4E,4214
18
+ otf_api/models/lifetime_stats.py,sha256=sQw0oaT5uSlCTZyMSEEhYJg7IdOzuxelTI3mzDBHNls,3055
19
+ otf_api/models/member_detail.py,sha256=CDDZg3Ow07U57yRqbm3i-BVha0cvCNOZ8QhN0pliU_A,6598
20
+ otf_api/models/member_membership.py,sha256=jZwHzwtVyMUr8dWGlFbMYj9qveCbiOblWW5szXDUFFo,1338
21
+ otf_api/models/member_purchases.py,sha256=Ne7ByEbGTqTJhuEyCgywWe8I3nc-D46qw09up7ys38s,1627
22
+ otf_api/models/mixins.py,sha256=VR5EeweySHhzaiqqnCr853Cpe1uK97cxY0IFEdf5T8w,2262
23
+ otf_api/models/notifications.py,sha256=AkmIfiIiU6wox_7puyenbhCX10SFvBD5eBAovcurRgY,833
24
+ otf_api/models/out_of_studio_workout_history.py,sha256=El5i0K2Td_sMReyfUKP-Iv1L1WgRx0ijjjnHzYvlCeY,1703
25
+ otf_api/models/performance_summary_detail.py,sha256=HmtAJIKkekYy2rJOQBxfQGsKJxuFZm7gP4Dauae-PqM,2711
26
+ otf_api/models/performance_summary_list.py,sha256=jv28jZJEOXOZtghhHhNR-4BPVBY3TpyiwHNKmnoTRcA,1692
27
+ otf_api/models/studio_detail.py,sha256=4HZXP6khjuFs7J7lokr3rMEDDpCwcb7OYJVJvzgly7U,3639
28
+ otf_api/models/studio_services.py,sha256=aGLQMQmjGVpI6YxzAl-mcp3Y9cHPXuH9dIqrl6E-78E,1665
29
+ otf_api/models/telemetry.py,sha256=_g-wtJDbaXENk1DqH0bbpJUsGepWDYraRIsIvpvDBU8,2531
30
+ otf_api/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ otf_api/utils.py,sha256=Af_Xg2QLoFqRzHOj4LtCIIqpRsdih-7HW1rJ8tUo8tE,3937
32
+ otf_api-0.9.1.dist-info/LICENSE,sha256=UaPT9ynYigC3nX8n22_rC37n-qmTRKLFaHrtUwF9ktE,1071
33
+ otf_api-0.9.1.dist-info/METADATA,sha256=SPUE5dzWt65jmeoSiWbCY-Tb84vO-x6kOg91kKlvlmg,2296
34
+ otf_api-0.9.1.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
35
+ otf_api-0.9.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.1
2
+ Generator: poetry-core 2.0.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
otf_api/auth.py DELETED
@@ -1,316 +0,0 @@
1
- import typing
2
- from datetime import datetime, timedelta
3
- from logging import getLogger
4
- from typing import Any
5
-
6
- import jwt
7
- from pycognito import AWSSRP, Cognito, MFAChallengeException
8
- from pycognito.exceptions import TokenVerificationException
9
- from pydantic import Field
10
- from pydantic.config import ConfigDict
11
-
12
- from otf_api.models.base import OtfItemBase
13
-
14
- if typing.TYPE_CHECKING:
15
- from boto3.session import Session
16
- from botocore.config import Config
17
-
18
- LOGGER = getLogger(__name__)
19
- CLIENT_ID = "1457d19r0pcjgmp5agooi0rb1b" # from otlive
20
- USER_POOL_ID = "us-east-1_dYDxUeyL1"
21
-
22
-
23
- class OtfCognito(Cognito):
24
- _device_key: str | None = None
25
-
26
- def __init__(
27
- self,
28
- user_pool_id: str,
29
- client_id: str,
30
- user_pool_region: str | None = None,
31
- username: str | None = None,
32
- id_token: str | None = None,
33
- refresh_token: str | None = None,
34
- access_token: str | None = None,
35
- client_secret: str | None = None,
36
- access_key: str | None = None,
37
- secret_key: str | None = None,
38
- session: "Session|None" = None,
39
- botocore_config: "Config|None" = None,
40
- boto3_client_kwargs: dict[str, Any] | None = None,
41
- device_key: str | None = None,
42
- ):
43
- super().__init__(
44
- user_pool_id,
45
- client_id,
46
- user_pool_region=user_pool_region,
47
- username=username,
48
- id_token=id_token,
49
- refresh_token=refresh_token,
50
- access_token=access_token,
51
- client_secret=client_secret,
52
- access_key=access_key,
53
- secret_key=secret_key,
54
- session=session,
55
- botocore_config=botocore_config,
56
- boto3_client_kwargs=boto3_client_kwargs,
57
- )
58
- self.device_key = device_key
59
-
60
- @property
61
- def device_key(self) -> str | None:
62
- return self._device_key
63
-
64
- @device_key.setter
65
- def device_key(self, value: str | None):
66
- if not value:
67
- if self._device_key:
68
- LOGGER.debug("Clearing device key")
69
- self._device_key = value
70
- return
71
-
72
- redacted_value = value[:4] + "*" * (len(value) - 8) + value[-4:]
73
- LOGGER.debug(f"Setting device key: {redacted_value}")
74
- self._device_key = value
75
-
76
- def _set_tokens(self, tokens: dict[str, Any]):
77
- """Set the tokens and device metadata from the response.
78
-
79
- Args:
80
- tokens (dict): The response from the Cognito service.
81
- """
82
- super()._set_tokens(tokens)
83
-
84
- if new_metadata := tokens["AuthenticationResult"].get("NewDeviceMetadata"):
85
- self.device_key = new_metadata["DeviceKey"]
86
-
87
- def authenticate(self, password: str, client_metadata: dict[str, Any] | None = None, device_key: str | None = None):
88
- """
89
- Authenticate the user using the SRP protocol. Overridden to add `confirm_device` call.
90
-
91
- Args:
92
- password (str): The user's password
93
- client_metadata (dict, optional): Any additional client metadata to send to Cognito
94
- """
95
- aws = AWSSRP(
96
- username=self.username,
97
- password=password,
98
- pool_id=self.user_pool_id,
99
- client_id=self.client_id,
100
- client=self.client,
101
- client_secret=self.client_secret,
102
- )
103
- try:
104
- tokens = aws.authenticate_user(client_metadata=client_metadata)
105
- except MFAChallengeException as mfa_challenge:
106
- self.mfa_tokens = mfa_challenge.get_tokens()
107
- raise mfa_challenge
108
-
109
- # Set the tokens and device metadata
110
- self._set_tokens(tokens)
111
-
112
- if not device_key:
113
- # Confirm the device so we can use the refresh token
114
- aws.confirm_device(tokens)
115
- else:
116
- self.device_key = device_key
117
- try:
118
- self.renew_access_token()
119
- except TokenVerificationException:
120
- LOGGER.error("Failed to renew access token. Confirming device.")
121
- self.device_key = None
122
- aws.confirm_device(tokens)
123
-
124
- def check_token(self, renew: bool = True) -> bool:
125
- """
126
- Checks the exp attribute of the access_token and either refreshes
127
- the tokens by calling the renew_access_tokens method or does nothing
128
- :param renew: bool indicating whether to refresh on expiration
129
- :return: bool indicating whether access_token has expired
130
- """
131
- if not self.access_token:
132
- raise AttributeError("Access Token Required to Check Token")
133
- now = datetime.now() # noqa
134
- dec_access_token = jwt.decode(self.access_token, options={"verify_signature": False})
135
-
136
- exp = datetime.fromtimestamp(dec_access_token["exp"]) # noqa
137
- if now > exp - timedelta(minutes=15):
138
- expired = True
139
- if renew:
140
- self.renew_access_token()
141
- else:
142
- expired = False
143
- return expired
144
-
145
- def renew_access_token(self):
146
- """Sets a new access token on the User using the cached refresh token and device metadata."""
147
- auth_params = {"REFRESH_TOKEN": self.refresh_token}
148
- self._add_secret_hash(auth_params, "SECRET_HASH")
149
-
150
- if self.device_key:
151
- LOGGER.debug("Using device key for refresh token")
152
- auth_params["DEVICE_KEY"] = self.device_key
153
-
154
- refresh_response = self.client.initiate_auth(
155
- ClientId=self.client_id, AuthFlow="REFRESH_TOKEN_AUTH", AuthParameters=auth_params
156
- )
157
- self._set_tokens(refresh_response)
158
-
159
- @classmethod
160
- def from_token(
161
- cls, access_token: str, id_token: str, refresh_token: str | None = None, device_key: str | None = None
162
- ) -> "OtfCognito":
163
- """Create an OtfCognito instance from an id token.
164
-
165
- Args:
166
- access_token (str): The access token.
167
- id_token (str): The id token.
168
- refresh_token (str, optional): The refresh token. Defaults to None.
169
- device_key (str, optional): The device key. Defaults
170
-
171
- Returns:
172
- OtfCognito: The user instance
173
- """
174
- cognito = OtfCognito(
175
- USER_POOL_ID,
176
- CLIENT_ID,
177
- access_token=access_token,
178
- id_token=id_token,
179
- refresh_token=refresh_token,
180
- device_key=device_key,
181
- )
182
- cognito.verify_tokens()
183
- cognito.check_token()
184
- return cognito
185
-
186
- @classmethod
187
- def login(cls, username: str, password: str) -> "OtfCognito":
188
- """Create an OtfCognito instance from a username and password.
189
-
190
- Args:
191
- username (str): The username to login with.
192
- password (str): The password to login with.
193
-
194
- Returns:
195
- OtfCognito: The logged in user.
196
- """
197
- cognito_user = OtfCognito(USER_POOL_ID, CLIENT_ID, username=username)
198
- cognito_user.authenticate(password)
199
- cognito_user.check_token()
200
- return cognito_user
201
-
202
-
203
- class IdClaimsData(OtfItemBase):
204
- sub: str
205
- email_verified: bool
206
- iss: str
207
- cognito_username: str = Field(alias="cognito:username")
208
- given_name: str
209
- locale: str
210
- home_studio_id: str = Field(alias="custom:home_studio_id")
211
- aud: str
212
- event_id: str
213
- token_use: str
214
- auth_time: int
215
- exp: int
216
- is_migration: str = Field(alias="custom:isMigration")
217
- iat: int
218
- family_name: str
219
- email: str
220
- koji_person_id: str = Field(alias="custom:koji_person_id")
221
-
222
- @property
223
- def member_uuid(self) -> str:
224
- return self.cognito_username
225
-
226
- @property
227
- def full_name(self) -> str:
228
- return f"{self.given_name} {self.family_name}"
229
-
230
-
231
- class AccessClaimsData(OtfItemBase):
232
- sub: str
233
- device_key: str
234
- iss: str
235
- client_id: str
236
- event_id: str
237
- token_use: str
238
- scope: str
239
- auth_time: int
240
- exp: int
241
- iat: int
242
- jti: str
243
- username: str
244
-
245
- @property
246
- def member_uuid(self) -> str:
247
- return self.username
248
-
249
-
250
- class OtfUser(OtfItemBase):
251
- model_config = ConfigDict(arbitrary_types_allowed=True)
252
- cognito: OtfCognito
253
-
254
- def __init__(
255
- self,
256
- username: str | None = None,
257
- password: str | None = None,
258
- id_token: str | None = None,
259
- access_token: str | None = None,
260
- refresh_token: str | None = None,
261
- device_key: str | None = None,
262
- cognito: OtfCognito | None = None,
263
- ):
264
- """Create a User instance.
265
-
266
- Args:
267
- username (str, optional): The username to login with. Defaults to None.
268
- password (str, optional): The password to login with. Defaults to None.
269
- id_token (str, optional): The id token. Defaults to None.
270
- access_token (str, optional): The access token. Defaults to None.
271
- refresh_token (str, optional): The refresh token. Defaults to None.
272
- device_key (str, optional): The device key. Defaults to None.
273
- cognito (OtfCognito, optional): A Cognito instance. Defaults to None.
274
-
275
- Raises:
276
- ValueError: Must provide either username and password or id token
277
-
278
-
279
- """
280
- if cognito:
281
- cognito = cognito
282
- elif username and password:
283
- cognito = OtfCognito.login(username, password)
284
- elif access_token and id_token:
285
- cognito = OtfCognito.from_token(access_token, id_token, refresh_token, device_key)
286
- else:
287
- raise ValueError("Must provide either username and password or id token.")
288
-
289
- super().__init__(cognito=cognito)
290
-
291
- @property
292
- def member_id(self) -> str:
293
- return self.id_claims_data.cognito_username
294
-
295
- @property
296
- def member_uuid(self) -> str:
297
- return self.access_claims_data.sub
298
-
299
- @property
300
- def access_claims_data(self) -> AccessClaimsData:
301
- return AccessClaimsData(**self.cognito.access_claims)
302
-
303
- @property
304
- def id_claims_data(self) -> IdClaimsData:
305
- return IdClaimsData(**self.cognito.id_claims)
306
-
307
- def get_tokens(self) -> dict[str, str]:
308
- return {
309
- "id_token": self.cognito.id_token,
310
- "access_token": self.cognito.access_token,
311
- "refresh_token": self.cognito.refresh_token,
312
- }
313
-
314
- @property
315
- def device_key(self):
316
- return self.cognito.device_key
@@ -1,89 +0,0 @@
1
- from collections.abc import Hashable
2
- from datetime import datetime
3
- from typing import Any
4
-
5
- from pydantic import Field
6
-
7
- from otf_api.models.base import OtfItemBase
8
-
9
-
10
- class Class(OtfItemBase):
11
- class_id: int = Field(None, alias="classId")
12
- class_uuid: str = Field(None, alias="classUUId")
13
- mbo_studio_id: int | None = Field(None, alias="mboStudioId")
14
- mbo_class_id: int | None = Field(None, alias="mboClassId")
15
- mbo_class_schedule_id: int | None = Field(None, alias="mboClassScheduleId")
16
- mbo_program_id: int | None = Field(None, alias="mboProgramId")
17
- studio_id: int | None = Field(None, alias="studioId")
18
- coach_id: int | None = Field(None, alias="coachId")
19
- location_id: int | None = Field(None, alias="locationId")
20
- name: str | None = None
21
- description: str | None = None
22
- program_name: str | None = Field(None, alias="programName")
23
- program_schedule_type: str | None = Field(None, alias="programScheduleType")
24
- program_cancel_offset: int | None = Field(None, alias="programCancelOffset")
25
- max_capacity: int | None = Field(None, alias="maxCapacity")
26
- total_booked: int | None = Field(None, alias="totalBooked")
27
- web_capacity: int | None = Field(None, alias="webCapacity")
28
- web_booked: int | None = Field(None, alias="webBooked")
29
- total_booked_waitlist: int | None = Field(None, alias="totalBookedWaitlist")
30
- start_date_time: datetime | None = Field(None, alias="startDateTime")
31
- end_date_time: datetime | None = Field(None, alias="endDateTime")
32
- is_cancelled: bool | None = Field(None, alias="isCancelled")
33
- substitute: bool | None = None
34
- is_active: bool | None = Field(None, alias="isActive")
35
- is_waitlist_available: bool | None = Field(None, alias="isWaitlistAvailable")
36
- is_enrolled: bool | None = Field(None, alias="isEnrolled")
37
- is_hide_cancel: bool | None = Field(None, alias="isHideCancel")
38
- is_available: bool | None = Field(None, alias="isAvailable")
39
- room_number: int | None = Field(None, alias="roomNumber")
40
- created_by: str | None = Field(None, alias="createdBy")
41
- created_date: datetime | None = Field(None, alias="createdDate")
42
- updated_by: str | None = Field(None, alias="updatedBy")
43
- updated_date: datetime | None = Field(None, alias="updatedDate")
44
- is_deleted: bool | None = Field(None, alias="isDeleted")
45
- studio: dict[Hashable, Any] | None = Field(None, exclude=True)
46
- location: dict[Hashable, Any] | None = Field(None, exclude=True)
47
- coach: dict[Hashable, Any] | None = Field(None, exclude=True)
48
- attributes: dict[str, Any] | None = Field(None, exclude=True)
49
-
50
-
51
- class SavedBooking(OtfItemBase):
52
- class_booking_id: int = Field(..., alias="classBookingId")
53
- class_booking_uuid: str = Field(..., alias="classBookingUUId")
54
- studio_id: int | None = Field(None, alias="studioId")
55
- class_id: int | None = Field(None, alias="classId")
56
- is_intro: bool | None = Field(None, alias="isIntro")
57
- member_id: int | None = Field(None, alias="memberId")
58
- mbo_member_id: str | None = Field(None, alias="mboMemberId")
59
- mbo_class_id: int | None = Field(None, alias="mboClassId")
60
- mbo_visit_id: int | None = Field(None, alias="mboVisitId")
61
- mbo_waitlist_entry_id: int | None = Field(None, alias="mboWaitlistEntryId")
62
- mbo_sync_message: str | None = Field(None, alias="mboSyncMessage")
63
- status: str | None = None
64
- booked_date: datetime | None = Field(None, alias="bookedDate")
65
- checked_in_date: datetime | None = Field(None, alias="checkedInDate")
66
- cancelled_date: datetime | None = Field(None, alias="cancelledDate")
67
- created_by: str | None = Field(None, alias="createdBy")
68
- created_date: datetime | None = Field(None, alias="createdDate")
69
- updated_by: str | None = Field(None, alias="updatedBy")
70
- updated_date: datetime | None = Field(None, alias="updatedDate")
71
- is_deleted: bool | None = Field(None, alias="isDeleted")
72
- member: dict[Hashable, Any] | None = Field(None, exclude=True)
73
- otf_class: Class = Field(..., alias="class")
74
- custom_data: Any | None = Field(None, alias="customData", exclude=True)
75
- attributes: dict[str, Any] | None = Field(None, exclude=True)
76
-
77
-
78
- class BookClass(OtfItemBase):
79
- saved_bookings: list[SavedBooking] = Field(None, alias="savedBookings")
80
- mbo_response: list[dict[Hashable, Any]] | Any | None = Field(None, alias="mboResponse", exclude=True)
81
-
82
- @property
83
- def booking(self) -> SavedBooking:
84
- return self.saved_bookings[0]
85
-
86
- @property
87
- def booking_uuid(self) -> str:
88
- """Returns the booking UUID for the class. This can be used to cancel the class."""
89
- return self.booking.class_booking_uuid
@@ -1,49 +0,0 @@
1
- from collections.abc import Hashable
2
- from datetime import datetime
3
- from typing import Any
4
-
5
- from pydantic import Field
6
-
7
- from otf_api.models.base import OtfItemBase
8
-
9
-
10
- class Class(OtfItemBase):
11
- class_uuid: str = Field(..., alias="classUUId")
12
- name: str | None = None
13
- description: str | None = None
14
- start_date_time: datetime | None = Field(None, alias="startDateTime")
15
- end_date_time: datetime | None = Field(None, alias="endDateTime")
16
- is_available: bool | None = Field(None, alias="isAvailable")
17
- is_cancelled: bool | None = Field(None, alias="isCancelled")
18
- total_booked: int | None = Field(None, alias="totalBooked")
19
- mbo_class_id: int | None = Field(None, alias="mboClassId")
20
- mbo_studio_id: int | None = Field(None, alias="mboStudioId")
21
- studio: dict[Hashable, Any] | None = None
22
- coach: dict[Hashable, Any] | None = None
23
-
24
-
25
- class CancelBooking(OtfItemBase):
26
- class_booking_id: int = Field(..., alias="classBookingId")
27
- class_booking_uuid: str = Field(..., alias="classBookingUUId")
28
- otf_class: Class = Field(..., alias="class")
29
-
30
- studio_id: int | None = Field(None, alias="studioId")
31
- class_id: int | None = Field(None, alias="classId")
32
- is_intro: bool | None = Field(None, alias="isIntro")
33
- member_id: int | None = Field(None, alias="memberId")
34
- mbo_member_id: str | None = Field(None, alias="mboMemberId")
35
- mbo_class_id: int | None = Field(None, alias="mboClassId")
36
- mbo_visit_id: int | None = Field(None, alias="mboVisitId")
37
- mbo_waitlist_entry_id: int | None = Field(None, alias="mboWaitlistEntryId")
38
- mbo_sync_message: str | None = Field(None, alias="mboSyncMessage")
39
- status: str | None = None
40
- booked_date: datetime | None = Field(None, alias="bookedDate")
41
- checked_in_date: datetime | None = Field(None, alias="checkedInDate")
42
- cancelled_date: datetime | None = Field(None, alias="cancelledDate")
43
- created_by: str | None = Field(None, alias="createdBy")
44
- created_date: datetime | None = Field(None, alias="createdDate")
45
- updated_by: str | None = Field(None, alias="updatedBy")
46
- updated_date: datetime | None = Field(None, alias="updatedDate")
47
- is_deleted: bool | None = Field(None, alias="isDeleted")
48
- member: dict[Hashable, Any] | None = None
49
- continue_retry: bool | None = Field(None, alias="continueRetry")
@@ -1,106 +0,0 @@
1
- from datetime import datetime
2
-
3
- from pydantic import Field
4
-
5
- from otf_api.models.base import OtfItemBase
6
-
7
-
8
- class Location(OtfItemBase):
9
- location_id: int = Field(..., alias="locationId")
10
- location_uuid: str = Field(..., alias="locationUUId")
11
- studio_id: int = Field(..., alias="studioId")
12
- mbo_location_id: int = Field(..., alias="mboLocationId")
13
- mbo_studio_id: int = Field(..., alias="mboStudioId")
14
- latitude: float
15
- longitude: float
16
- address1: str
17
- address2: str | None = None
18
- city: str
19
- state: str
20
- phone: str
21
- postal_code: str = Field(..., alias="postalCode")
22
-
23
-
24
- class StudioLocation(OtfItemBase):
25
- bill_to_address: str = Field(..., alias="billToAddress")
26
- bill_to_address2: str = Field(..., alias="billToAddress2")
27
- bill_to_city: str = Field(..., alias="billToCity")
28
- bill_to_state: str = Field(..., alias="billToState")
29
- bill_to_postal_code: str = Field(..., alias="billToPostalCode")
30
- bill_to_region: str = Field(..., alias="billToRegion")
31
- bill_to_country_id: int = Field(..., alias="billToCountryId")
32
- bill_to_country: str = Field(..., alias="billToCountry")
33
- ship_to_address: str = Field(..., alias="shipToAddress")
34
- ship_to_address2: str | None = Field(None, alias="shipToAddress2")
35
- ship_to_city: str = Field(..., alias="shipToCity")
36
- ship_to_state: str = Field(..., alias="shipToState")
37
- ship_to_postal_code: str = Field(..., alias="shipToPostalCode")
38
- ship_to_region: str = Field(..., alias="shipToRegion")
39
- ship_to_country_id: int = Field(..., alias="shipToCountryId")
40
- ship_to_country: str = Field(..., alias="shipToCountry")
41
- physical_address: str = Field(..., alias="physicalAddress")
42
- physical_address2: str | None = Field(None, alias="physicalAddress2")
43
- physical_city: str = Field(..., alias="physicalCity")
44
- physical_state: str = Field(..., alias="physicalState")
45
- physical_postal_code: str = Field(..., alias="physicalPostalCode")
46
- physical_region: str = Field(..., alias="physicalRegion")
47
- physical_country_id: int = Field(..., alias="physicalCountryId")
48
- physical_country: str = Field(..., alias="physicalCountry")
49
- phone_number: str = Field(..., alias="phoneNumber")
50
- latitude: str
51
- longitude: str
52
-
53
-
54
- class FavoriteStudio(OtfItemBase):
55
- studio_id: int = Field(..., alias="studioId")
56
- studio_uuid: str = Field(..., alias="studioUUId")
57
- mbo_studio_id: int = Field(..., alias="mboStudioId")
58
- studio_name: str = Field(..., alias="studioName")
59
- area_id: int | None = Field(None, alias="areaId")
60
- market_id: int | None = Field(None, alias="marketId")
61
- state_id: int | None = Field(None, alias="stateId")
62
- studio_physical_location_id: int = Field(..., alias="studioPhysicalLocationId")
63
- studio_number: str = Field(..., alias="studioNumber")
64
- description: str | None = None
65
- studio_version: str | None = Field(None, alias="studioVersion")
66
- studio_token: str = Field(..., alias="studioToken")
67
- studio_status: str = Field(..., alias="studioStatus")
68
- open_date: datetime = Field(..., alias="openDate")
69
- studio_type_id: int = Field(..., alias="studioTypeId")
70
- pos_type_id: int | None = Field(None, alias="posTypeId")
71
- logo_url: str | None = Field(None, alias="logoUrl")
72
- page_color1: str | None = Field(None, alias="pageColor1")
73
- page_color2: str | None = Field(None, alias="pageColor2")
74
- page_color3: str | None = Field(None, alias="pageColor3")
75
- page_color4: str | None = Field(None, alias="pageColor4")
76
- accepts_visa_master_card: bool = Field(..., alias="acceptsVisaMasterCard")
77
- accepts_american_express: bool = Field(..., alias="acceptsAmericanExpress")
78
- accepts_discover: bool = Field(..., alias="acceptsDiscover")
79
- accepts_ach: bool = Field(..., alias="acceptsACH")
80
- sms_package_enabled: bool | None = Field(None, alias="smsPackageEnabled")
81
- allows_dashboard_access: bool | None = Field(None, alias="allowsDashboardAccess")
82
- pricing_level: str | None = Field(None, alias="pricingLevel")
83
- contact_email: str = Field(..., alias="contactEmail")
84
- time_zone: str = Field(..., alias="timeZone")
85
- environment: str
86
- allows_cr_waitlist: bool = Field(..., alias="allowsCRWaitlist")
87
- cr_waitlist_flag_last_updated: datetime = Field(..., alias="crWaitlistFlagLastUpdated")
88
- is_integrated: bool = Field(..., alias="isIntegrated")
89
- created_by: str = Field(..., alias="createdBy")
90
- created_date: datetime = Field(..., alias="createdDate")
91
- updated_date: datetime = Field(..., alias="updatedDate")
92
- is_deleted: bool = Field(..., alias="isDeleted")
93
- locations: list[Location]
94
- studio_location: StudioLocation = Field(..., alias="studioLocation")
95
-
96
-
97
- class FavoriteStudioList(OtfItemBase):
98
- studios: list[FavoriteStudio]
99
-
100
- @property
101
- def studio_ids(self) -> list[int]:
102
- return [studio.studio_id for studio in self.studios]
103
-
104
- @property
105
- def studio_uuids(self) -> list[str]:
106
- return [studio.studio_uuid for studio in self.studios]
@@ -1,21 +0,0 @@
1
- from datetime import datetime
2
-
3
- from pydantic import Field
4
-
5
- from otf_api.models.base import OtfItemBase
6
-
7
-
8
- class LatestAgreement(OtfItemBase):
9
- file_url: str = Field(..., alias="fileUrl")
10
- agreement_id: int = Field(..., alias="agreementId")
11
- agreement_uuid: str = Field(..., alias="agreementUUId")
12
- agreement_datetime: datetime = Field(..., alias="agreementDatetime")
13
- agreement_type_id: int = Field(..., alias="agreementTypeId")
14
- platform: None
15
- locale: str
16
- version: str
17
- created_by: str = Field(..., alias="createdBy")
18
- created_date: datetime = Field(..., alias="createdDate")
19
- updated_by: str = Field(..., alias="updatedBy")
20
- updated_date: datetime = Field(..., alias="updatedDate")
21
- is_deleted: bool = Field(..., alias="isDeleted")
@@ -1,34 +0,0 @@
1
- from pydantic import Field
2
-
3
- from otf_api.models.base import OtfItemBase
4
-
5
-
6
- class MaxHr(OtfItemBase):
7
- type: str
8
- value: int
9
-
10
-
11
- class Zone(OtfItemBase):
12
- start_bpm: int = Field(..., alias="startBpm")
13
- end_bpm: int = Field(..., alias="endBpm")
14
-
15
-
16
- class Zones(OtfItemBase):
17
- gray: Zone
18
- blue: Zone
19
- green: Zone
20
- orange: Zone
21
- red: Zone
22
-
23
-
24
- class HistoryItem(OtfItemBase):
25
- max_hr: MaxHr = Field(..., alias="maxHr")
26
- zones: Zones
27
- change_from_previous: int = Field(..., alias="changeFromPrevious")
28
- change_bucket: str = Field(..., alias="changeBucket")
29
- assigned_at: str = Field(..., alias="assignedAt")
30
-
31
-
32
- class TelemetryHrHistory(OtfItemBase):
33
- member_uuid: str = Field(..., alias="memberUuid")
34
- history: list[HistoryItem]
@@ -1,13 +0,0 @@
1
- from pydantic import Field
2
-
3
- from otf_api.models.base import OtfItemBase
4
-
5
-
6
- class MaxHr(OtfItemBase):
7
- type: str
8
- value: int
9
-
10
-
11
- class TelemetryMaxHr(OtfItemBase):
12
- member_uuid: str = Field(..., alias="memberUuid")
13
- max_hr: MaxHr = Field(..., alias="maxHr")