from celery import Celery, app from rowers.rower_rules import is_workout_user import time from django_rq import job from rowers.tasks import handle_rp3_async_workout from rowsandall_app.settings import ( C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, RP3_CLIENT_ID, RP3_CLIENT_KEY, RP3_REDIRECT_URI, RP3_CLIENT_SECRET, UPLOAD_SERVICE_URL, UPLOAD_SERVICE_SECRET ) from rowers.utils import myqueue # All the functionality needed to connect to Runkeeper from rowers.imports import * # Python import gzip import base64 from io import BytesIO from rowers.utils import dologging import django_rq queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('high') oauth_data = { 'client_id': RP3_CLIENT_ID, 'client_secret': RP3_CLIENT_SECRET, 'redirect_uri': RP3_REDIRECT_URI, 'autorization_uri': "https://rp3rowing-app.com/oauth/authorize?", 'content_type': 'application/x-www-form-urlencoded', # 'content_type': 'application/json', 'tokenname': 'rp3token', 'refreshtokenname': 'rp3refreshtoken', 'expirydatename': 'rp3tokenexpirydate', 'bearer_auth': False, 'base_url': "https://rp3rowing-app.com/oauth/token", 'scope': 'read,write', } graphql_url = "https://rp3rowing-app.com/graphql" # Checks if user has UnderArmour token, renews them if they are expired def rp3_open(user): return imports_open(user, oauth_data) # Refresh ST token using refresh token def do_refresh_token(refreshtoken): # pragma: no cover return imports_do_refresh_token(refreshtoken, oauth_data) # Exchange access code for long-lived access token def get_token(code): # pragma: no cover post_data = { "client_id": RP3_CLIENT_KEY, "grant_type": "authorization_code", "code": code, "redirect_uri": RP3_REDIRECT_URI, "client_secret": RP3_CLIENT_SECRET, } response = requests.post( "https://rp3rowing-app.com/oauth/token", data=post_data, verify=False, ) try: token_json = response.json() thetoken = token_json['access_token'] expires_in = token_json['expires_in'] refresh_token = token_json['refresh_token'] except KeyError: thetoken = 0 expires_in = 0 refresh_token = 0 return thetoken, expires_in, refresh_token # Make authorization URL including random string def make_authorization_url(request): # pragma: no cover return imports_make_authorization_url(oauth_data) def get_rp3_workout_list(user): auth_token = rp3_open(user) headers = {'Authorization': 'Bearer ' + auth_token} get_workouts_list = """{ workouts{ id executed_at } }""" response = requests.post( url=graphql_url, headers=headers, json={'query': get_workouts_list} ) return response def get_rp3_workouts(rower, do_async=True): # pragma: no cover try: auth_token = rp3_open(rower.user) except NoTokenError: return 0 res = get_rp3_workout_list(rower.user) if (res.status_code != 200): return 0 s = '{d}'.format(d=res.json()) dologging('rp3_import.log', s) workouts_list = pd.json_normalize(res.json()['data']['workouts']) try: rp3ids = workouts_list['id'].values workouts_list.set_index('id', inplace=True) except (KeyError, IndexError): return 0 knownrp3ids = uniqify([ w.uploadedtorp3 for w in Workout.objects.filter(user=rower) ]) newids = [rp3id for rp3id in rp3ids if rp3id not in knownrp3ids] for id in newids: startdatetime = workouts_list.loc[id, 'executed_at'] dologging('rp3_import.log', startdatetime) _ = myqueue( queuehigh, handle_rp3_async_workout, rower.user.id, auth_token, id, startdatetime, 10, ) return 1 def download_rp3_file(url, auth_token, filename): # pragma: no cover headers = {'Authorization': 'Bearer ' + auth_token} res = requests.get(url, headers=headers) if res.status_code == 200: with open(filename, 'wb') as f: f.write(res.content) return res.status_code def get_rp3_workout_token(workout_id, auth_token, waittime=3, max_attempts=20): # pragma: no cover headers = {'Authorization': 'Bearer ' + auth_token} get_download_link = """{ download(workout_id: """ + str(workout_id) + """, type:csv){ id status link } }""" have_link = False download_url = '' counter = 0 while not have_link: response = requests.post( url=graphql_url, headers=headers, json={'query': get_download_link} ) if response.status_code != 200: have_link = True workout_download_details = pd.json_normalize( response.json()['data']['download']) if workout_download_details.iat[0, 1] == 'ready': download_url = workout_download_details.iat[0, 2] have_link = True counter += 1 if counter > max_attempts: have_link = True time.sleep(waittime) return download_url def get_rp3_workout_link(user, workout_id, waittime=3, max_attempts=20): # pragma: no cover auth_token = rp3_open(user) return get_rp3_workout_token(workout_id, auth_token, waittime=waittime, max_attempts=max_attempts) def get_rp3_workout(user, workout_id, startdatetime=None): # pragma: no cover url = get_rp3_workout_link(user, workout_id) filename = 'media/RP3Import_'+str(workout_id)+'.csv' auth_token = rp3_open(user) if not startdatetime: startdatetime = str(timezone.now()) status_code = download_rp3_file(url, auth_token, filename) if status_code != 200: return 0 userid = user.id uploadoptions = { 'secret': UPLOAD_SERVICE_SECRET, 'user': userid, 'file': filename, 'workouttype': 'dynamic', 'boattype': '1x', 'rp3id': workout_id, 'startdatetime': startdatetime, } session = requests.session() newHeaders = {'Content-type': 'application/json', 'Accept': 'text/plain'} session.headers.update(newHeaders) response = session.post(UPLOAD_SERVICE_URL, json=uploadoptions) if response.status_code != 200: return 0 return response.json()['id']