From 7237d1b53608ad5a0eee469f77bc793eb48c3953 Mon Sep 17 00:00:00 2001 From: kbe Date: Thu, 17 Jul 2025 16:51:13 +0200 Subject: [PATCH] feat(sessions): Retrieve all available courses from API --- book_crossfit.py | 117 +++++++++++++++++++++++++++++++------------ retrieve_sessions.py | 64 +++++++++++++++++++++++ 2 files changed, 150 insertions(+), 31 deletions(-) create mode 100755 retrieve_sessions.py diff --git a/book_crossfit.py b/book_crossfit.py index cecd20a..17c04ee 100755 --- a/book_crossfit.py +++ b/book_crossfit.py @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env python3 import requests import json @@ -54,11 +54,18 @@ class CrossFitBooker: "username": USERNAME, "password": PASSWORD })) - + if not response.ok: print(f"First login step failed: {response.status_code} - {response.text}") return False + login_data = response.json() + # self.auth_token = login_data["data"]["token"] + self.user_id = str(login_data["data"]["user"]["id_user"]) + + # Uncomment to see user_id + # print(self.user_id) + # Second login endpoint response = self.session.post( "https://sport.nubapp.com/api/v4/login", @@ -72,9 +79,11 @@ class CrossFitBooker: if response.ok: login_data = response.json() - # print(login_data) self.auth_token = login_data.get("token") - self.user_id = str(login_data.get("id_user")) + + # Uncomment to see Bearer token + # print(self.auth_token) + if self.auth_token and self.user_id: print("Successfully logged in") return True @@ -86,40 +95,86 @@ class CrossFitBooker: return False def get_available_sessions(self, start_date: datetime, end_date: datetime) -> Optional[Dict]: - """Fetch available sessions from the API""" + """Fetch available sessions from the API with comprehensive error handling""" if not self.auth_token or not self.user_id: - print("Not authenticated") + print("Authentication required - missing token or user ID") return None + url = "https://sport.nubapp.com/api/v4/activities/getActivitiesCalendar.php" + + # Prepare request components + headers = { + "Authorization": f"Bearer {self.auth_token}", + "Content-Type": "application/x-www-form-urlencoded", + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0", + "Nubapp-Origin": "user_apps" + } + + request_data = { + "app_version": APP_VERSION, + "id_application": APPLICATION_ID, + "id_user": self.user_id, + "start_timestamp": start_date.strftime("%d-%m-%Y"), + "end_timestamp": end_date.strftime("%d-%m-%Y"), + "id_category_activity": CATEGORY_ID + } + try: - headers = {"Authorization": f"Bearer {self.auth_token}"} - - request_data = urlencode({ - "app_version": APP_VERSION, - "id_application": APPLICATION_ID, - "id_user": self.user_id, - "start_timestamp": start_date.strftime("%d-%m-%Y"), - "end_timestamp": end_date.strftime("%d-%m-%Y"), - "id_category_activity": CATEGORY_ID - }) - + # Debug output + print("\n--- Request Details ---") + print(f"URL: {url}") + print(f"Headers: {json.dumps(headers, indent=2)}") + print(f"Payload: {request_data}") + + # Make the request response = self.session.post( - "https://sport.nubapp.com/api/v4/activities/getActivitiesCalendar.php", + url, headers=headers, - data=request_data - ) + data=urlencode(request_data), + timeout=10 + ) - - print(headers) - print(request_data) - print(response.json()) - - return response.json() if response.ok else None + # Debug raw response + print("\n--- Response ---") + print(f"Status Code: {response.status_code}") + print(f"Headers: {response.headers}") + print(f"Content: {response.text}") - except Exception as e: - print(f"Error getting sessions: {str(e)}") + # Handle response + if response.status_code == 200: + try: + json_response = response.json() + if json_response.get("success", False): + return json_response + else: + print(f"API reported failure: {json_response.get('message')}") + return None + except ValueError: + print("Failed to decode JSON response") + return None + elif response.status_code == 400: + print("400 Bad Request - likely missing or invalid parameters") + print("Verify these parameters:") + print(f"- app_version: {APP_VERSION}") + print(f"- id_application: {APPLICATION_ID}") + print(f"- id_user: {self.user_id}") + print(f"- Date format (DD-MM-YYYY): {start_date.strftime('%d-%m-%Y')} to {end_date.strftime('%d-%m-%Y')}") + print(f"- id_category_activity: {CATEGORY_ID}") + return None + elif response.status_code == 401: + print("401 Unauthorized - token may be expired or invalid") + return None + else: + print(f"Unexpected status code: {response.status_code}") + return None + + except requests.exceptions.RequestException as e: + print(f"Request failed: {str(e)}") return None - + except Exception as e: + print(f"Unexpected error: {str(e)}") + return None + def book_session(self, session_id: str) -> bool: """Book a specific session""" if not self.auth_token or not self.user_id: @@ -263,6 +318,6 @@ if __name__ == "__main__": booker = CrossFitBooker() booker.login() sessions = booker.get_available_sessions(datetime.strptime("21-07-2025", "%d-%m-%Y"), datetime.strptime("27-07-2025", "%d-%m-%Y")) - print(sessions) - # booker.run_booking_cycle(datetime.now()) + # print(sessions) + booker.run_booking_cycle(datetime.now()) # booker.run() \ No newline at end of file diff --git a/retrieve_sessions.py b/retrieve_sessions.py new file mode 100755 index 0000000..9344992 --- /dev/null +++ b/retrieve_sessions.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import requests +from datetime import datetime, timedelta +from urllib.parse import urlencode +import json + +def get_crossfit_sessions(auth_token, user_id, start_date, end_date): + """Fetch CrossFit sessions with proper error handling""" + url = "https://sport.nubapp.com/api/v4/activities/getActivitiesCalendar.php" + + headers = { + "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:140.0) Gecko/20100101 Firefox/140.0", + "Authorization": f"Bearer {auth_token}", + "Content-Type": "application/x-www-form-urlencoded", + "Nubapp-Origin": "user_apps" + } + + params = { + "app_version": "5.09.21", + "id_application": "81560887", + "id_user": user_id, + "start_timestamp": start_date.strftime("%d-%m-%Y"), + "end_timestamp": end_date.strftime("%d-%m-%Y"), + "id_category_activity": "677" + } + + try: + response = requests.post( + url, + headers=headers, + data=urlencode(params), + timeout=10 + ) + + if response.status_code == 200: + return response.json() + else: + print(f"API Error: {response.status_code} - {response.text}") + return None + + except requests.exceptions.RequestException as e: + print(f"Request failed: {str(e)}") + return None + +# Example usage +if __name__ == "__main__": + # Replace with your actual token and user ID + AUTH_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE3NTI3NjE3OTMsImV4cCI6MTc2ODY2Mjk5Mywicm9sZXMiOlsiUk9MRV9VU0VSIl0sImlkX3VzZXIiOjMxOTE0MjksImlkX2FwcGxpY2F0aW9uIjo4MTU2MDg4NywicGFzc3dvcmRfaGFzaCI6ImEzZGZiOGQzY2NhNTA5NmJhYzYxMWM4MmEwMzYyYTg2ODc3MjQ4MjIiLCJhdXRoZW50aWNhdGlvbl90eXBlIjoiYXBpIiwidXNlcm5hbWUiOiJLZXZpbjg0MDcifQ.l3NmfHISvrErpYMPBR-nvBT1ijOnDLFLgBUr9icg-WVwpA4ff1IXUd4kSJCP2pxj8ziG8eNpLitHFQGp27-b_cdb6f5usSH4tysWHRD__M4o_htYbSAD1qJcw1kwSRw4ZWGCoLqh8c8SGd5LK3ZmddSv3ECx3BK7CvyZggDfeSDK-hDCyJejWi6L3UeV49_aa5a49Ll6Kb6GvOZVzIuU8xikbpsIrLStOo26sNjW-_2dw2gvBUuDz6InGTvUHIJgfvR2s6RlyUH8imyprsv8hFHP-oeqmIXYdvKi9FH4v8EAsmYfENcx4NHJHHck8y8EeS2e3kOO1HyWLPURQDBppA" + USER_ID = "3191429" + + # Set date range (today + 7 days) + start_date = datetime.now() + end_date = start_date + timedelta(days=7) + + sessions = get_crossfit_sessions(AUTH_TOKEN, USER_ID, start_date, end_date) + + if sessions and sessions.get("success"): + print("Successfully retrieved sessions:") + print(json.dumps(sessions, indent=2)) + else: + print("Failed to retrieve sessions") + if sessions: + print(f"API Message: {sessions.get('message')}") \ No newline at end of file