adding rp3 auto import
This commit is contained in:
@@ -207,6 +207,10 @@ class Command(BaseCommand):
|
|||||||
if user_is_not_basic(r.user):
|
if user_is_not_basic(r.user):
|
||||||
c2stuff.get_c2_workouts(r)
|
c2stuff.get_c2_workouts(r)
|
||||||
|
|
||||||
|
rowers = Rower.objects.filter(rp3_auto_import=True)
|
||||||
|
for r in rowers:
|
||||||
|
if user_is_not_basic(r.user):
|
||||||
|
res = rp3stuff.get_rp3_workouts(r)
|
||||||
|
|
||||||
messages = Message.objects.filter(mailbox_id = workoutmailbox.id)
|
messages = Message.objects.filter(mailbox_id = workoutmailbox.id)
|
||||||
message_ids = [m.id for m in messages]
|
message_ids = [m.id for m in messages]
|
||||||
|
|||||||
@@ -995,6 +995,8 @@ class Rower(models.Model):
|
|||||||
rp3refreshtoken = models.TextField(default='',max_length=1000,
|
rp3refreshtoken = models.TextField(default='',max_length=1000,
|
||||||
blank=True,null=True)
|
blank=True,null=True)
|
||||||
|
|
||||||
|
rp3_auto_import = models.BooleanField(default=False)
|
||||||
|
|
||||||
trainingpeaks_auto_export = models.BooleanField(default=False)
|
trainingpeaks_auto_export = models.BooleanField(default=False)
|
||||||
|
|
||||||
polartoken = models.CharField(default='',max_length=1000,blank=True,null=True)
|
polartoken = models.CharField(default='',max_length=1000,blank=True,null=True)
|
||||||
@@ -3836,6 +3838,7 @@ class RowerExportForm(ModelForm):
|
|||||||
'strava_auto_import',
|
'strava_auto_import',
|
||||||
'strava_auto_delete',
|
'strava_auto_delete',
|
||||||
'trainingpeaks_auto_export',
|
'trainingpeaks_auto_export',
|
||||||
|
'rp3_auto_import'
|
||||||
]
|
]
|
||||||
|
|
||||||
# Simple form to set rower's Functional Threshold Power
|
# Simple form to set rower's Functional Threshold Power
|
||||||
|
|||||||
@@ -12,16 +12,24 @@ import gzip
|
|||||||
import base64
|
import base64
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
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 (
|
from rowsandall_app.settings import (
|
||||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
||||||
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
|
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
|
||||||
RP3_CLIENT_ID, RP3_CLIENT_SECRET,
|
RP3_CLIENT_ID, RP3_CLIENT_SECRET,
|
||||||
RP3_REDIRECT_URI,RP3_CLIENT_KEY,
|
RP3_REDIRECT_URI,RP3_CLIENT_KEY,
|
||||||
RP3_CLIENT_ID, RP3_CLIENT_KEY, RP3_REDIRECT_URI, RP3_CLIENT_SECRET,
|
RP3_CLIENT_ID, RP3_CLIENT_KEY, RP3_REDIRECT_URI, RP3_CLIENT_SECRET,
|
||||||
UPLOAD_SERVICE_URL, UPLOAD_SERVICE_SECRET
|
UPLOAD_SERVICE_URL, UPLOAD_SERVICE_SECRET
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from rowers.tasks import handle_rp3_async_workout
|
||||||
|
|
||||||
|
|
||||||
from celery import Celery,app
|
from celery import Celery,app
|
||||||
from django_rq import job
|
from django_rq import job
|
||||||
@@ -60,14 +68,14 @@ def do_refresh_token(refreshtoken):
|
|||||||
def get_token(code):
|
def get_token(code):
|
||||||
client_auth = requests.auth.HTTPBasicAuth(RP3_CLIENT_KEY, RP3_CLIENT_SECRET)
|
client_auth = requests.auth.HTTPBasicAuth(RP3_CLIENT_KEY, RP3_CLIENT_SECRET)
|
||||||
post_data = {
|
post_data = {
|
||||||
"client_id":RP3_CLIENT_KEY,
|
"client_id":RP3_CLIENT_KEY,
|
||||||
"grant_type": "authorization_code",
|
"grant_type": "authorization_code",
|
||||||
"code": code,
|
"code": code,
|
||||||
"redirect_uri":RP3_REDIRECT_URI,
|
"redirect_uri":RP3_REDIRECT_URI,
|
||||||
"client_secret": RP3_CLIENT_SECRET,
|
"client_secret": RP3_CLIENT_SECRET,
|
||||||
}
|
}
|
||||||
headers = {
|
headers = {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
}
|
}
|
||||||
|
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
@@ -107,13 +115,49 @@ def get_rp3_workout_list(user):
|
|||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
url=graphql_url,
|
url=graphql_url,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json={'query': get_workouts_list}
|
json={'query': get_workouts_list}
|
||||||
)
|
)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def get_rp3_workouts(rower,do_async=True):
|
||||||
|
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
|
||||||
|
|
||||||
|
workouts_list = pd.json_normalize(res.json()['data']['workouts'])
|
||||||
|
rp3ids = workouts_list['id'].values
|
||||||
|
workouts_list.set_index('id',inplace=True)
|
||||||
|
|
||||||
|
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']
|
||||||
|
|
||||||
|
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):
|
def download_rp3_file(url,auth_token,filename):
|
||||||
headers = {'Authorization': 'Bearer ' + auth_token }
|
headers = {'Authorization': 'Bearer ' + auth_token }
|
||||||
|
|
||||||
@@ -129,11 +173,11 @@ def get_rp3_workout_token(workout_id,auth_token,waittime=3,max_attempts=20):
|
|||||||
headers = {'Authorization': 'Bearer ' + auth_token }
|
headers = {'Authorization': 'Bearer ' + auth_token }
|
||||||
|
|
||||||
get_download_link = """{
|
get_download_link = """{
|
||||||
download(workout_id: """ + str(workout_id) + """, type:csv){
|
download(workout_id: """ + str(workout_id) + """, type:csv){
|
||||||
id
|
id
|
||||||
status
|
status
|
||||||
link
|
link
|
||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
have_link = False
|
have_link = False
|
||||||
@@ -144,7 +188,7 @@ def get_rp3_workout_token(workout_id,auth_token,waittime=3,max_attempts=20):
|
|||||||
url=graphql_url,
|
url=graphql_url,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
json={'query': get_download_link}
|
json={'query': get_download_link}
|
||||||
)
|
)
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
have_link = True
|
have_link = True
|
||||||
|
|||||||
@@ -2872,7 +2872,7 @@ def add2(x, y,debug=False,**kwargs):
|
|||||||
graphql_url = "https://rp3rowing-app.com/graphql"
|
graphql_url = "https://rp3rowing-app.com/graphql"
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,debug=False,**kwargs):
|
def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts,debug=False,**kwargs):
|
||||||
headers = {'Authorization': 'Bearer ' + rp3token }
|
headers = {'Authorization': 'Bearer ' + rp3token }
|
||||||
|
|
||||||
get_download_link = """{
|
get_download_link = """{
|
||||||
@@ -2886,7 +2886,7 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,debug=False,**k
|
|||||||
have_link = False
|
have_link = False
|
||||||
download_url = ''
|
download_url = ''
|
||||||
counter = 0
|
counter = 0
|
||||||
max_attempts = 20
|
#max_attempts = 20
|
||||||
waittime = 3
|
waittime = 3
|
||||||
while not have_link:
|
while not have_link:
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
@@ -2895,6 +2895,7 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,debug=False,**k
|
|||||||
json={'query': get_download_link}
|
json={'query': get_download_link}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
have_link = True
|
have_link = True
|
||||||
|
|
||||||
@@ -2915,6 +2916,7 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,debug=False,**k
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
filename = 'media/RP3Import_'+str(rp3id)+'.csv'
|
filename = 'media/RP3Import_'+str(rp3id)+'.csv'
|
||||||
|
|
||||||
res = requests.get(download_url,headers=headers)
|
res = requests.get(download_url,headers=headers)
|
||||||
|
|
||||||
if not startdatetime:
|
if not startdatetime:
|
||||||
@@ -2933,7 +2935,7 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,debug=False,**k
|
|||||||
'file': filename,
|
'file': filename,
|
||||||
'workouttype':'dynamic',
|
'workouttype':'dynamic',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'rp3id':rp3id,
|
'rp3id':int(rp3id),
|
||||||
'startdatetime':startdatetime,
|
'startdatetime':startdatetime,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
{% block main %}
|
{% block main %}
|
||||||
<h1>Available on RP3</h1>
|
<h1>Available on RP3</h1>
|
||||||
{% if workouts %}
|
{% if workouts %}
|
||||||
|
<p><a href="/rowers/workout/rp3import/all/">Import all New</a></p>
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<li class="grid_4">
|
<li class="grid_4">
|
||||||
<table width="70%" class="listtable">
|
<table width="70%" class="listtable">
|
||||||
|
|||||||
@@ -569,6 +569,7 @@ urlpatterns = [
|
|||||||
re_path(r'^workout/c2import/all/(?P<page>\d+)/$',views.workout_getc2workout_all,name='workout_getc2workout_all'),
|
re_path(r'^workout/c2import/all/(?P<page>\d+)/$',views.workout_getc2workout_all,name='workout_getc2workout_all'),
|
||||||
re_path(r'^workout/rp3import/(?P<externalid>\d+)/$',views.workout_getrp3importview,
|
re_path(r'^workout/rp3import/(?P<externalid>\d+)/$',views.workout_getrp3importview,
|
||||||
name='workout_getrp3importview'),
|
name='workout_getrp3importview'),
|
||||||
|
re_path(r'^workout/rp3import/all/$',views.workout_getrp3workout_all,name='workout_getrp3workout_all'),
|
||||||
re_path(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/$',views.workout_getimportview,name='workout_getimportview'),
|
re_path(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/$',views.workout_getimportview,name='workout_getimportview'),
|
||||||
re_path(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all,name='workout_getstravaworkout_all'),
|
re_path(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all,name='workout_getstravaworkout_all'),
|
||||||
re_path(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next,name='workout_getstravaworkout_next'),
|
re_path(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next,name='workout_getstravaworkout_next'),
|
||||||
|
|||||||
@@ -1002,7 +1002,7 @@ def workout_rp3import_view(request,userid=0):
|
|||||||
if (r.stravatoken == '') or (r.stravatoken is None):
|
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||||
s = "Token doesn't exist. Need to authorize"
|
s = "Token doesn't exist. Need to authorize"
|
||||||
return HttpResponseRedirect("/rowers/me/stravaauthorize/")
|
return HttpResponseRedirect("/rowers/me/stravaauthorize/")
|
||||||
message = "Something went wrong in workout_stravaimport_view"
|
message = "Something went wrong in workout_rp3import_view"
|
||||||
messages.error(request,message)
|
messages.error(request,message)
|
||||||
url = reverse('workouts_view')
|
url = reverse('workouts_view')
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
@@ -1700,6 +1700,25 @@ def workout_getc2workout_all(request,page=1,message=""):
|
|||||||
url = reverse('workouts_view')
|
url = reverse('workouts_view')
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def workout_getrp3workout_all(request):
|
||||||
|
try:
|
||||||
|
thetoken = rp3_open(request.user)
|
||||||
|
except NoTokenError:
|
||||||
|
return HttpResponseRedirect("/rowers/me/rp3authorize/")
|
||||||
|
|
||||||
|
r = getrequestrower(request)
|
||||||
|
|
||||||
|
result = rp3stuff.get_rp3_workouts(r,do_async=True)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
messages.info(request,'Your RP3 workouts will be imported in the coming few minutes')
|
||||||
|
else:
|
||||||
|
messages.error(request,'Your RP3 workouts import failed')
|
||||||
|
|
||||||
|
url = reverse('workouts_view')
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
# List of workouts available on Concept2 logbook - for import
|
# List of workouts available on Concept2 logbook - for import
|
||||||
@login_required()
|
@login_required()
|
||||||
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
|
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
|
||||||
@@ -1807,6 +1826,7 @@ def workout_getrp3importview(request,externalid):
|
|||||||
token,
|
token,
|
||||||
externalid,
|
externalid,
|
||||||
startdatetime,
|
startdatetime,
|
||||||
|
20,
|
||||||
)
|
)
|
||||||
|
|
||||||
#id = rp3stuff.get_rp3_workout(r.user,externalid,startdatetime=startdatetime)
|
#id = rp3stuff.get_rp3_workout(r.user,externalid,startdatetime=startdatetime)
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ import datetime
|
|||||||
import iso8601
|
import iso8601
|
||||||
import rowers.c2stuff as c2stuff
|
import rowers.c2stuff as c2stuff
|
||||||
from rowers.c2stuff import c2_open
|
from rowers.c2stuff import c2_open
|
||||||
|
from rowers.rp3stuff import rp3_open
|
||||||
from rowers.runkeeperstuff import runkeeper_open
|
from rowers.runkeeperstuff import runkeeper_open
|
||||||
from rowers.sporttracksstuff import sporttracks_open
|
from rowers.sporttracksstuff import sporttracks_open
|
||||||
from rowers.tpstuff import tp_open
|
from rowers.tpstuff import tp_open
|
||||||
|
|||||||
Reference in New Issue
Block a user