Skip to content

Commit

Permalink
feat(examples_sync): add example scripts for challenge tracker, class…
Browse files Browse the repository at this point in the history
… bookings, studio, and workout functionalities

Add example scripts to demonstrate the usage of the OtfSync API for
various functionalities including challenge tracking, class bookings,
studio information, and workout data. These examples serve as a guide
for users to understand how to interact with the API and retrieve
relevant data.

feat(otf_api): introduce OtfSync class for synchronous API interactions

Add a new OtfSync class to the otf_api module to facilitate
synchronous interactions with the Orangetheory Fitness API. This class
provides methods for booking classes, retrieving member details,
accessing performance summaries, and more. It aims to simplify the
process of making API requests and handling responses in a
synchronous manner.
  • Loading branch information
NodeJSmith committed Dec 23, 2024
1 parent e67f187 commit c0cbce3
Show file tree
Hide file tree
Showing 6 changed files with 1,451 additions and 1 deletion.
112 changes: 112 additions & 0 deletions examples_sync/challenge_tracker_examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import os
from getpass import getpass

from otf_api import OtfSync
from otf_api.models import ChallengeType, EquipmentType

USERNAME = os.getenv("OTF_EMAIL") or input("Enter your OTF email: ")
PASSWORD = os.getenv("OTF_PASSWORD") or getpass("Enter your OTF password: ")


def main():
with OtfSync(USERNAME, PASSWORD) as otf:
# challenge tracker content is an overview of the challenges OTF runs
# and your participation in them
challenge_tracker_content = otf.get_challenge_tracker_content()
print(challenge_tracker_content.benchmarks[0].model_dump_json(indent=4))

"""
{
"equipment_id": 2,
"equipment_name": "Treadmill",
"years": [
{
"year": "2024",
"is_participated": false,
"in_progress": false
},
...
],
"logo_url": "https://otf-icons.s3.amazonaws.com/benchmarks/Treadmill.png"
}
"""

print(challenge_tracker_content.challenges[0].model_dump_json(indent=4))
"""
{
"challenge_category_id": 10,
"challenge_sub_category_id": 8,
"challenge_name": "Catch Me If You Can 3G",
"years": [
{
"year": "2024",
"is_participated": false,
"in_progress": false
},
...
],
"logo_url": "https://otf-icons.s3.amazonaws.com/challenges/CatchMeIfYouCan.png"
}
"""

# challenge tracker details are detailed information about specific challenges
# this endpoint takes an equipment type and a challenge type as arguments
tread_challenge_details = otf.get_challenge_tracker_detail(EquipmentType.Treadmill, ChallengeType.Other)
print(tread_challenge_details.details[0].model_dump_json(indent=4))

"""
{
"challenge_category_id": 10,
"challenge_sub_category_id": null,
"equipment_id": 2,
"equipment_name": "Treadmill",
"metric_entry": {
"title": "22 MIN",
"equipment_id": 2,
"entry_type": "Distance",
"metric_key": "22MIN",
"min_value": "0.16093440000000003",
"max_value": "8.04672"
},
"challenge_name": "Catch me If You Can",
"logo_url": "https://otf-icons.s3.amazonaws.com/challenges/CatchMeIfYouCan.png",
"best_record": 1.40012928,
"last_record": 1.40012928,
"previous_record": 1.40012928,
"unit": "km",
"goals": null,
"challenge_histories": [
{
"challenge_objective": "None",
"challenge_id": 449906,
"studio_id": 1267,
"studio_name": "AnyTown OH - East",
"start_date": "2024-02-06 00:00:00",
"end_date": "2024-02-06 23:59:00",
"total_result": 1.40012928,
"is_finished": true,
"benchmark_histories": [
{
"studio_name": "AnyTown OH - East",
"equipment_id": 2,
"result": 1.40012928,
"date_created": "2024-02-06 16:01:26",
"date_updated": "2024-02-06 16:01:26",
"class_time": "2024-02-06 09:45:00",
"challenge_sub_category_id": null,
"class_id": 86842386,
"substitute_id": 1,
"weight_lbs": 0,
"workout_type_id": null,
"workout_id": null,
"linked_challenges": []
}
]
}
]
}
"""


if __name__ == "__main__":
main()
124 changes: 124 additions & 0 deletions examples_sync/class_bookings_examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import os
from datetime import datetime
from getpass import getpass

from otf_api import OtfSync
from otf_api.models.classes import DoW

USERNAME = os.getenv("OTF_EMAIL") or input("Enter your OTF email: ")
PASSWORD = os.getenv("OTF_PASSWORD") or getpass("Enter your OTF password: ")


def main():
with OtfSync(USERNAME, PASSWORD) as otf:
resp = otf.get_bookings(start_date=datetime.today().date())
print(resp.model_dump_json(indent=4))

studios = otf.search_studios_by_geo(40.7831, 73.9712, distance=100)

studio_uuids = [studio.studio_uuid for studio in studios.studios]

# To get upcoming classes you can call the `get_classes` method
# You can pass a list of studio_uuids or, if you want to get classes from your home studio, leave it empty
# this also takes a start date, end date, and limit - these are not sent to the API, they are used in the
# client to filter the results
classes = otf.get_classes(studio_uuids, day_of_week=[DoW.TUESDAY, DoW.THURSDAY, DoW.SATURDAY])

print(classes.classes[0].model_dump_json(indent=4))

"""
{
"id": "0e39ef70-7403-49c1-8605-4a72643bd201",
"ot_base_class_uuid": "08cebfdb-e127-48d4-8a7f-e6ea4dd85c18",
"starts_at": "2024-06-13 10:00:00+00:00",
"starts_at_local": "2024-06-13 05:00:00",
"ends_at": "2024-06-13 11:00:00+00:00",
"ends_at_local": "2024-06-13 06:00:00",
"name": "Orange 3G",
"type": "ORANGE_60",
"studio": ...,
"coach": ...,
"max_capacity": 36,
"booking_capacity": 36,
"waitlist_size": 0,
"full": false,
"waitlist_available": false,
"canceled": false,
"mbo_class_id": "30809",
"mbo_class_schedule_id": "2655",
"mbo_class_description_id": "102",
"created_at": "2024-05-14 10:33:32.406000+00:00",
"updated_at": "2024-06-13 01:58:55.233000+00:00"
}
"""

# You can also get the classes that you have booked
# You can pass a start_date, end_date, status, and limit as arguments

bookings = otf.get_bookings()

print("Latest Upcoming Class:")
print(bookings.bookings[-1].model_dump_json(indent=4))

"""
{
"class_booking_id": 870700285,
"class_booking_uuid": "a36d76b1-0a55-4143-b96b-646e7520ca39",
"studio_id": 1234,
"class_id": 376344282,
"is_intro": false,
"member_id": 234488148,
"status": "Booked",
"booked_date": "2024-09-10T04:26:11Z",
"checked_in_date": null,
"cancelled_date": null,
"created_date": "2024-09-10T04:26:11Z",
"updated_date": "2024-09-10T04:26:13Z",
"is_deleted": false,
"waitlist_position": null,
"otf_class": {
"starts_at_local": "2024-09-28T10:30:00",
"ends_at_local": "2024-09-28T11:20:00",
"name": "Tread 50",
"class_uuid": "82ec9b55-950a-484f-818f-cd2344ce83fd",
"is_available": true,
"is_cancelled": false,
"program_name": "Group Fitness",
"coach_id": 1204786,
"studio": {
"studio_uuid": "49e360d1-f8ef-4091-a23f-61b321cb283c",
"studio_name": "AnyTown OH - East",
"description": "",
"status": "Active",
"time_zone": "America/Chicago",
"studio_id": 1267,
"allows_cr_waitlist": true
},
"coach": {
"coach_uuid": "973516a8-0c6b-41ec-916c-1da9913b9a16",
"name": "Friendly",
"first_name": "Friendly",
"last_name": "Coach"
},
"location": {
"address_one": "123 S Main St",
"address_two": null,
"city": "AnyTown",
"country": null,
"distance": null,
"latitude": 91.73407745,
"location_name": null,
"longitude": -80.92264626,
"phone_number": "2042348963",
"postal_code": "11111",
"state": "Ohio"
},
"virtual_class": null
},
"is_home_studio": true
}
"""


if __name__ == "__main__":
main()
73 changes: 73 additions & 0 deletions examples_sync/studio_examples.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import os
from getpass import getpass

from otf_api import OtfSync

USERNAME = os.getenv("OTF_EMAIL") or input("Enter your OTF email: ")
PASSWORD = os.getenv("OTF_PASSWORD") or getpass("Enter your OTF password: ")


def main():
with OtfSync(USERNAME, PASSWORD) as otf:
# if you need to figure out what studios are in an area, you can call `search_studios_by_geo`
# which takes latitude, longitude, distance, page_index, and page_size as arguments
# but you'll generally just need the first 3
# same as with classes, you can leave it blank and get the studios within 50 miles of your home studio
studios_by_geo = otf.search_studios_by_geo()
print(studios_by_geo.studios[0].model_dump_json(indent=4))

"""
{
"studio_id": 1297,
"studio_uuid": "8645fb2b-ef66-4d9d-bda1-f508091ec891",
"mbo_studio_id": 8612481,
"studio_number": "05414",
"studio_name": "AnyTown OH - East",
"studio_physical_location_id": 494,
"time_zone": "America/Chicago",
"contact_email": "[email protected]",
"studio_token": "ec2459b2-32b5-4b7e-9759-55270626925a",
"environment": "PROD",
"pricing_level": "",
"tax_rate": "0.000000",
"accepts_visa_master_card": true,
"accepts_american_express": true,
"accepts_discover": true,
"accepts_ach": false,
"is_integrated": true,
"description": "",
"studio_version": "",
"studio_status": "Active",
"open_date": "2017-01-13 00:00:00",
"re_open_date": "2020-05-26 00:00:00",
"studio_type_id": 2,
"sms_package_enabled": false,
"allows_dashboard_access": false,
"allows_cr_waitlist": true,
"cr_waitlist_flag_last_updated": "2020-07-09 02:43:55+00:00",
"royalty_rate": 0,
"marketing_fund_rate": 0,
"commission_percent": 0,
"is_mobile": null,
"is_otbeat": null,
"distance": 0.0,
"studio_location": ...,
"studio_location_localized": ...,
"studio_profiles": {
"is_web": true,
"intro_capacity": 1,
"is_crm": true
},
"social_media_links": ...
}
"""

# if you need to get detailed information about a studio, you can call `get_studio_detail`
# which takes a studio_uuid as an argument, but you can leave it blank to get details about your home studio
# this one has a result structure very much like the previous one
studio_detail = otf.get_studio_detail()
print(studio_detail.model_dump_json(indent=4))


if __name__ == "__main__":
main()
Loading

0 comments on commit c0cbce3

Please sign in to comment.