266 lines
6.9 KiB
Python
266 lines
6.9 KiB
Python
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
from __future__ import unicode_literals
|
|
from __future__ import unicode_literals, absolute_import
|
|
# 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')
|
|
|
|
from rowers.utils import myqueue
|
|
|
|
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_SECRET,
|
|
RP3_REDIRECT_URI,RP3_CLIENT_KEY,
|
|
RP3_CLIENT_ID, RP3_CLIENT_KEY, RP3_REDIRECT_URI, RP3_CLIENT_SECRET,
|
|
UPLOAD_SERVICE_URL, UPLOAD_SERVICE_SECRET
|
|
)
|
|
|
|
from rowers.tasks import handle_rp3_async_workout
|
|
|
|
|
|
from celery import Celery,app
|
|
from django_rq import job
|
|
import time
|
|
#from async_messages import message_user,messages
|
|
|
|
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',
|
|
}
|
|
|
|
from rowers.rower_rules import is_workout_user
|
|
|
|
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
|
|
client_auth = requests.auth.HTTPBasicAuth(RP3_CLIENT_KEY, RP3_CLIENT_SECRET)
|
|
post_data = {
|
|
"client_id":RP3_CLIENT_KEY,
|
|
"grant_type": "authorization_code",
|
|
"code": code,
|
|
"redirect_uri":RP3_REDIRECT_URI,
|
|
"client_secret": RP3_CLIENT_SECRET,
|
|
}
|
|
headers = {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
}
|
|
|
|
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):
|
|
r = Rower.objects.get(user=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 not rp3id in knownrp3ids]
|
|
|
|
for id in newids:
|
|
startdatetime = workouts_list.loc[id,'executed_at']
|
|
dologging('rp3_import.log',startdatetime)
|
|
|
|
job = 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
|
|
r = Rower.objects.get(user=user)
|
|
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'
|
|
|
|
r = Rower.objects.get(user=user)
|
|
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']
|