Private
Public Access
1
0

runkeeper retired, updated sporttraclks

This commit is contained in:
Sander Roosendaal
2021-05-21 11:30:57 +02:00
parent b58ba932fd
commit b53b56f909
21 changed files with 74 additions and 906 deletions

29
filename Normal file

File diff suppressed because one or more lines are too long

View File

@@ -46,7 +46,6 @@ class RowerInline(admin.StackedInline):
'sporttrackstoken','sporttrackstokenexpirydate', 'sporttrackstoken','sporttrackstokenexpirydate',
'sporttracksrefreshtoken', 'sporttracksrefreshtoken',
'sporttracks_auto_export', 'sporttracks_auto_export',
'mapmyfitness_auto_export',
'tptoken','tptokenexpirydate','tprefreshtoken', 'tptoken','tptokenexpirydate','tprefreshtoken',
'trainingpeaks_auto_export', 'trainingpeaks_auto_export',
'polartoken','polartokenexpirydate', 'polartoken','polartokenexpirydate',
@@ -55,7 +54,6 @@ class RowerInline(admin.StackedInline):
'stravatoken','stravatokenexpirydate','stravarefreshtoken', 'stravatoken','stravatokenexpirydate','stravarefreshtoken',
'stravaexportas','strava_auto_export', 'stravaexportas','strava_auto_export',
'strava_auto_import', 'strava_auto_import',
'runkeepertoken','runkeeper_auto_export',
'garmintoken','garminrefreshtoken')}), 'garmintoken','garminrefreshtoken')}),
('Team', ('Team',
{'fields':('friends','privacy','team')}), {'fields':('friends','privacy','team')}),

View File

@@ -825,14 +825,9 @@ def make_authorization_url(request): # pragma: no cover
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
# Get workout from C2 ID # Get workout from C2 ID
def get_workout(user,c2id,do_async=False): def get_workout(user,c2id,do_async=True):
r = Rower.objects.get(user=user) r = Rower.objects.get(user=user)
if (r.c2token == '') or (r.c2token is None): # pragma: no cover thetoken = c2_open(user)
s = "Token doesn't exist. Need to authorize"
return custom_exception_handler(401,s) ,0
elif (timezone.now()>r.tokenexpirydate):
s = "Token expired. Needs to refresh."
return custom_exception_handler(401,s),0
job = myqueue(queuehigh, job = myqueue(queuehigh,
handle_c2_getworkout, handle_c2_getworkout,

View File

@@ -988,7 +988,6 @@ class Rower(models.Model):
sporttracksrefreshtoken = models.CharField(default='',max_length=200, sporttracksrefreshtoken = models.CharField(default='',max_length=200,
blank=True,null=True) blank=True,null=True)
sporttracks_auto_export = models.BooleanField(default=False) sporttracks_auto_export = models.BooleanField(default=False)
mapmyfitness_auto_export = models.BooleanField(default=False)
tptoken = models.CharField(default='',max_length=1000,blank=True,null=True) tptoken = models.CharField(default='',max_length=1000,blank=True,null=True)
tptokenexpirydate = models.DateTimeField(blank=True,null=True) tptokenexpirydate = models.DateTimeField(blank=True,null=True)
tprefreshtoken = models.CharField(default='',max_length=1000, tprefreshtoken = models.CharField(default='',max_length=1000,
@@ -1037,9 +1036,6 @@ class Rower(models.Model):
strava_auto_export = models.BooleanField(default=False) strava_auto_export = models.BooleanField(default=False)
strava_auto_import = models.BooleanField(default=False) strava_auto_import = models.BooleanField(default=False)
strava_auto_delete = models.BooleanField(default=False) strava_auto_delete = models.BooleanField(default=False)
runkeepertoken = models.CharField(default='',max_length=200,
blank=True,null=True)
runkeeper_auto_export = models.BooleanField(default=False)
privacychoices = ( privacychoices = (
@@ -3198,7 +3194,6 @@ class Workout(models.Model):
uploadedtostrava = models.BigIntegerField(default=0) uploadedtostrava = models.BigIntegerField(default=0)
uploadedtosporttracks = models.BigIntegerField(default=0) uploadedtosporttracks = models.BigIntegerField(default=0)
uploadedtotp = models.BigIntegerField(default=0) uploadedtotp = models.BigIntegerField(default=0)
uploadedtorunkeeper = models.BigIntegerField(default=0)
uploadedtogarmin = models.BigIntegerField(default=0) uploadedtogarmin = models.BigIntegerField(default=0)
uploadedtorp3 = models.BigIntegerField(default=0) uploadedtorp3 = models.BigIntegerField(default=0)
uploadedtonk = models.BigIntegerField(default=0) uploadedtonk = models.BigIntegerField(default=0)
@@ -3279,7 +3274,6 @@ class TombStone(models.Model):
uploadedtostrava = models.BigIntegerField(default=0) uploadedtostrava = models.BigIntegerField(default=0)
uploadedtosporttracks = models.BigIntegerField(default=0) uploadedtosporttracks = models.BigIntegerField(default=0)
uploadedtotp = models.BigIntegerField(default=0) uploadedtotp = models.BigIntegerField(default=0)
uploadedtorunkeeper = models.BigIntegerField(default=0)
uploadedtonk = models.BigIntegerField(default=0) uploadedtonk = models.BigIntegerField(default=0)
@receiver(models.signals.pre_delete,sender=Workout) @receiver(models.signals.pre_delete,sender=Workout)
@@ -3289,7 +3283,6 @@ def create_tombstone_on_delete(sender, instance, **kwargs):
uploadedtoc2 = instance.uploadedtoc2, uploadedtoc2 = instance.uploadedtoc2,
uploadedtostrava = instance.uploadedtostrava, uploadedtostrava = instance.uploadedtostrava,
uploadedtotp = instance.uploadedtotp, uploadedtotp = instance.uploadedtotp,
uploadedtorunkeeper = instance.uploadedtorunkeeper,
uploadedtonk = instance.uploadedtonk uploadedtonk = instance.uploadedtonk
) )
t.save() t.save()
@@ -3864,8 +3857,6 @@ class RowerExportForm(ModelForm):
'c2_auto_export', 'c2_auto_export',
'c2_auto_import', 'c2_auto_import',
'nk_auto_import', 'nk_auto_import',
'mapmyfitness_auto_export',
'runkeeper_auto_export',
'sporttracks_auto_export', 'sporttracks_auto_export',
'strava_auto_export', 'strava_auto_export',
'strava_auto_import', 'strava_auto_import',
@@ -4208,8 +4199,6 @@ class RowerImportExportForm(ModelForm):
'polar_auto_import', 'polar_auto_import',
'c2_auto_export', 'c2_auto_export',
'c2_auto_import', 'c2_auto_import',
'mapmyfitness_auto_export',
'runkeeper_auto_export',
'sporttracks_auto_export', 'sporttracks_auto_export',
'strava_auto_export', 'strava_auto_export',
'strava_auto_import', 'strava_auto_import',

View File

@@ -1,530 +0,0 @@
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 *
import re
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
from rowers.utils import myqueue
from rowers.rower_rules import is_workout_user
from rowsandall_app.settings import (
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
RUNKEEPER_CLIENT_ID, RUNKEEPER_CLIENT_SECRET,RUNKEEPER_REDIRECT_URI,
)
from rowers.tasks import handle_runkeeper_sync
oauth_data = {
'client_id': RUNKEEPER_CLIENT_ID,
'client_secret': RUNKEEPER_CLIENT_SECRET,
'redirect_uri': RUNKEEPER_REDIRECT_URI,
'autorization_uri': "https://www.runkeeper.com/apps/authorize",
'content_type': 'application/x-www-form-urlencoded',
'tokenname': 'runkeepertoken',
'refreshtokenname': None,
'expirydatename': None,
'bearer_auth': True,
'base_url': "https://runkeeper.com/apps/token",
'headers': {'user-agent': 'sanderroosendaal'},
'scope':'write',
}
import numpy
def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
t = []
lat = []
lon = []
for d in lijst:
t.append(d[tname])
lat.append(d[latname])
lon.append(d[lonname])
return [np.array(t),np.array(lat),np.array(lon)]
def splitrunkeeperdata(lijst,xname,yname):
x = []
y = []
for d in lijst:
x.append(d[xname])
y.append(d[yname])
return [np.array(x),np.array(y)]
# Checks if user has SportTracks token, renews them if they are expired
def runkeeper_open(user):
return imports_open(user,oauth_data)
# Exchange access code for long-lived access token
def get_token(code):
return imports_get_token(code,oauth_data)
# Make authorization URL including random string
def make_authorization_url(request): # pragma: no cover
return imports_make_authorization_url(oauth_data)
# Get list of workouts available on Runkeeper
def get_runkeeper_workout_list(user):
r = Rower.objects.get(user=user)
if (r.runkeepertoken == '') or (r.runkeepertoken is None):
s = "Token doesn't exist. Need to authorize"
return custom_exception_handler(401,s)
else:
# ready to fetch. Hurray
authorizationstring = str('Bearer ' + r.runkeepertoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
url = "https://api.runkeeper.com/fitnessActivities"
s = requests.get(url,headers=headers)
return s
# Get workout summary data by Runkeeper ID
def get_workout(user,runkeeperid,do_async=False):
r = Rower.objects.get(user=user)
if (r.runkeepertoken == '') or (r.runkeepertoken is None): # pragma: no cover
return custom_exception_handler(401,s)
s = "Token doesn't exist. Need to authorize"
else:
# ready to fetch. Hurray
authorizationstring = str('Bearer ' + r.runkeepertoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
url = "https://api.runkeeper.com/fitnessActivities/"+str(runkeeperid)
s = requests.get(url,headers=headers)
try:
data = s.json()
except ValueError: # pragma: no cover
data = {}
return data,"Something went wrong with the workout import"
strokedata = pd.DataFrame.from_dict({
key: pd.Series(value) for key, value in data.items()
})
return data,strokedata
# Create Workout Data for upload to SportTracks
def createrunkeeperworkoutdata(w):
filename = w.csvfilename
try:
row = rowingdata(csvfile=filename)
except: # pragma: no cover
return 0
try:
averagehr = int(row.df[' HRCur (bpm)'].mean())
maxhr = int(row.df[' HRCur (bpm)'].max())
except KeyError: # pragma: no cover
averagehr = 0
maxhr = 0
duration = w.duration.hour*3600
duration += w.duration.minute*60
duration += w.duration.second
duration += +1.0e-6*w.duration.microsecond
try:
t = row.df.loc[:,'TimeStamp (sec)'].values-row.df.loc[:,'TimeStamp (sec)'].iloc[0]
except KeyError: # pragma: no cover
return pd.DataFrame()
t[0] = t[1]
d = row.df.loc[:,'cum_dist'].values
d[0] = d[1]
t = t.astype(int)
d = d.astype(int)
spm = row.df[' Cadence (stokes/min)'].astype(int)
spm[0] = spm[1]
hr = row.df[' HRCur (bpm)'].astype(int)
haslatlon=1
try:
lat = row.df[' latitude'].values
lon = row.df[' longitude'].values
if not lat.std() and not lon.std(): # pragma: no cover
haslatlon = 0
except KeyError: # pragma: no cover
haslatlon = 0
t = t.tolist()
hr = hr.tolist()
d = d.tolist()
# path data
if haslatlon:
lat = lat.tolist()
lon = lon.tolist()
locdata = []
for e in zip(t,lat,lon):
point = {'timestamp':e[0],
'latitude':e[1],
'longitude':e[2],
'altitude':0,
"type":"gps"}
locdata.append(point)
hrdata = []
for e in zip(t,hr):
point = {'timestamp':e[0],
'heart_rate':e[1]
}
hrdata.append(point)
distancedata = []
for e in zip(t,d):
point = {'timestamp':e[0],
'distance':e[1]
}
distancedata.append(point)
st = w.startdatetime.astimezone(pytz.timezone(w.timezone))
start_time = st.strftime("%a, %d %b %Y %H:%M:%S")
try:
newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
except TypeError:
newnotes = 'from '+w.workoutsource+' via rowsandall.com'
if haslatlon:
data = {
"type": "Rowing",
"start_time": start_time,
"total_distance": int(w.distance),
"duration": duration,
"notes": newnotes,
"average_heart_rate": averagehr,
"path": locdata,
"distance": distancedata,
"heart_rate": hrdata,
"post_to_twitter":"false",
"post_to_facebook":"false",
}
else:
data = {
"type": "Rowing",
"start_time": start_time,
"total_distance": int(w.distance),
"duration": duration,
"notes": newnotes,
"avg_heartrate": averagehr,
"distance": distancedata,
"heart_rate": hrdata,
"post_to_twitter":"false",
"post_to_facebook":"false",
}
return data
# Obtain Runkeeper Workout ID from the response returned on successful
# upload
def getidfromresponse(response):
uri = response.headers["Location"]
tester = re.compile('^\/fitnessActivities\/(\d+)$')
id = int(tester.match(uri).group(1))
return int(id)
def geturifromid(access_token,id): # pragma: no cover
authorizationstring = str('Bearer ' + access_token)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
import urllib
url = "https://api.runkeeper.com/fitnessActivities/"+str(id)
response = requests.get(url,headers=headers)
try:
me_json = response.json()
except:
return ''
try:
res = me_json['uri']
except KeyError:
res = ''
return res
# Get user id, having access token
# Handy for checking if the API access is working
def get_userid(access_token):
authorizationstring = str('Bearer ' + access_token)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
import urllib
url = "https://api.runkeeper.com/user"
response = requests.get(url,headers=headers)
try:
me_json = response.json()
except: # pragma: no cover
return ''
try:
res = me_json['userID']
except KeyError: # pragma: no cover
res = ''
return str(res)
def default(o): # pragma: no cover
if isinstance(o, numpy.int64): return int(o)
raise TypeError
def workout_runkeeper_upload(user,w,asynchron=False): # pragma: no cover
message = "Uploading to Runkeeper"
rkid = 0
r = w.user
thetoken = runkeeper_open(r.user)
# ready to upload. Hurray
if (is_workout_user(user,w)):
data = createrunkeeperworkoutdata(w)
if not data:
message = "Data error in Runkeeper Upload"
rkid = 0
return message, rkid
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json',
'Content-Length':'nnn'}
url = "https://api.runkeeper.com/fitnessActivities"
if asynchron:
job = myqueue(queue,handle_runkeeper_sync,
w.id,url,headers,json.dumps(data,default=default))
return "Asynchronous sync",0
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
# check for duplicate error first
if (response.status_code == 409 ):
message = "Duplicate error"
w.uploadedtorunkeeper = -1
rkid = -1
w.save()
return message, rkid
elif (response.status_code == 201 or response.status_code==200):
rkid = getidfromresponse(response)
rkuri = geturifromid(thetoken,rkid)
w.uploadedtorunkeeper = rkid
w.save()
return 'Successfully synchronized to Runkeeper',rkid
else:
s = response
message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text)
rkid = 0
return message, rkid
else:
message = "You are not authorized to upload this workout"
rkid = 0
return message, rkid
return message,rkid
# Create workout from RunKeeper Data
def add_workout_from_data(user,importid,data,strokedata,source='runkeeper',
workoutsource='runkeeper'):
# To Do - add utcoffset to time
workouttype = data['type']
if workouttype not in [x[0] for x in Workout.workouttypes]:
workouttype = 'other'
try:
comments = data['notes']
except: # pragma: no cover
comments = ''
try:
utcoffset = tz(data['utcoffset'])
except:
utcoffset = 0
r = Rower.objects.get(user=user)
try:
rowdatetime = iso8601.parse_date(data['start_time'])
except iso8601.ParseError:
try: # pragma: no cover
rowdatetime = datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
except ValueError:
try:
rowdatetime = parser.parse(data['start_time'])
#rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
except: # pragma: no cover
rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
starttimeunix = arrow.get(rowdatetime).timestamp()
#starttimeunix = mktime(rowdatetime.utctimetuple())
starttimeunix += utcoffset*3600
try:
title = data['name']
except:
title = "Imported data"
res = splitrunkeeperdata(data['distance'],'timestamp','distance')
distance = res[1]
times_distance = res[0]
try:
l = data['path']
res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude')
times_location = res[0]
latcoord = res[1]
loncoord = res[2]
except: # pragma: no cover
times_location = times_distance
latcoord = np.zeros(len(times_distance))
loncoord = np.zeros(len(times_distance))
if workouttype in types.otwtypes:
workouttype = 'rower'
try: # pragma: no cover
res = splitrunkeeperdata(data['cadence'],'timestamp','cadence')
times_spm = res[0]
spm = res[1]
except KeyError:
times_spm = times_distance
spm = 0*times_distance
try:
res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate')
hr = res[1]
times_hr = res[0]
except KeyError: # pragma: no cover
times_hr = times_distance
hr = 0*times_distance
# create data series and remove duplicates
distseries = pd.Series(distance,index=times_distance)
distseries = distseries.groupby(distseries.index).first()
latseries = pd.Series(latcoord,index=times_location)
try:
latseries = latseries.groupby(latseries.index).first()
except TypeError: # pragma: no cover
latseries = 0.0*distseries
lonseries = pd.Series(loncoord,index=times_location)
try:
lonseries = lonseries.groupby(lonseries.index).first()
except TypeError: # pragma: no cover
lonseries = 0.0*distseries
spmseries = pd.Series(spm,index=times_spm)
spmseries = spmseries.groupby(spmseries.index).first()
hrseries = pd.Series(hr,index=times_hr)
try:
hrseries = hrseries.groupby(hrseries.index).first()
except TypeError: # pragma: no cover
hrseries = 0*distseries
# Create dicts and big dataframe
d = {
' Horizontal (meters)': distseries,
' latitude': latseries,
' longitude': lonseries,
' Cadence (stokes/min)': spmseries,
' HRCur (bpm)' : hrseries,
}
df = pd.DataFrame(d)
df = df.groupby(level=0).last()
cum_time = df.index.values
df[' ElapsedTime (sec)'] = cum_time
velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff()
df[' Power (watts)'] = 0.0*velo
nr_rows = len(velo.values)
df[' DriveLength (meters)'] = np.zeros(nr_rows)
df[' StrokeDistance (meters)'] = np.zeros(nr_rows)
df[' DriveTime (ms)'] = np.zeros(nr_rows)
df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows)
df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows)
df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows)
df[' lapIdx'] = np.zeros(nr_rows)
unixtime = cum_time+starttimeunix
try:
unixtime[0] = starttimeunix
except IndexError: # pragma: no cover
return (0,'No data to import')
df['TimeStamp (sec)'] = unixtime
dt = np.diff(cum_time).mean()
wsize = round(5./dt)
# velo2 = stravastuff.ewmovingaverage(velo,wsize)
# df[' Stroke500mPace (sec/500m)'] = 500./velo2
df = df.fillna(0)
df.sort_values(by='TimeStamp (sec)',ascending=True)
timestr = strftime("%Y%m%d-%H%M%S")
# csvfilename ='media/Import_'+str(importid)+'.csv'
csvfilename ='media/{code}_{importid}.csv'.format(
importid=importid,
code = uuid4().hex[:16]
)
res = df.to_csv(csvfilename+'.gz',index_label='index',
compression='gzip')
id,message = dataprep.save_workout_database(csvfilename,r,
workouttype=workouttype,
workoutsource='runkeeper',
title=title,
dosmooth=r.dosmooth,
notes=comments)
return (id,message)

View File

@@ -120,7 +120,14 @@ def get_workout(user,sporttracksid,do_async=False):
key: pd.Series(value) for key, value in data.items() key: pd.Series(value) for key, value in data.items()
}) })
return data,strokedata id,message = add_workout_from_data(
user,
sporttracksid,data,
strokedata,
source='sporttracks',
workoutsource='sporttracks')
return id
# Create Workout Data for upload to SportTracks # Create Workout Data for upload to SportTracks
def createsporttracksworkoutdata(w): def createsporttracksworkoutdata(w):

View File

@@ -25,7 +25,6 @@ from rowingdata import rowingdata as rdata
from datetime import timedelta from datetime import timedelta
from sqlalchemy import create_engine from sqlalchemy import create_engine
from rowers.imports import splituadata
#from celery import app #from celery import app
from rowers.celery import app from rowers.celery import app

View File

@@ -192,21 +192,6 @@
</a> </a>
{% endif %} {% endif %}
</li> </li>
<li id="export-rk">
{% if workout.uploadedtorunkeeper %}
<a href="https://runkeeper.com/user/{{ user|rkuserid }}/activity/{{ workout.uploadedtorunkeeper }}">
Runkeeper <i class="fas fa-check"></i>
</a>
{% elif user.rower.runkeepertoken == None or user.rower.runkeepertoken == '' %}
<a href="/rowers/me/runkeeperauthorize">
Connect to Runkeeper
</a>
{% else %}
<a href="/rowers/workout/{{ workout.id|encode }}/runkeeperuploadw/">
Runkeeper
</a>
{% endif %}
</li>
<li id="export-tp"> <li id="export-tp">
{% if workout.uploadedtotp %} {% if workout.uploadedtotp %}
<a href="https://app.trainingpeaks.com"> <a href="https://app.trainingpeaks.com">

View File

@@ -40,7 +40,6 @@
<li id="concept2"><a href="/rowers/workout/c2list/">Concept2</a></li> <li id="concept2"><a href="/rowers/workout/c2list/">Concept2</a></li>
<li id="nklink"><a href="/rowers/workout/nkimport/">NK Logbook</a></li> <li id="nklink"><a href="/rowers/workout/nkimport/">NK Logbook</a></li>
<li id="strava"><a href="/rowers/workout/stravaimport/">Strava</a></li> <li id="strava"><a href="/rowers/workout/stravaimport/">Strava</a></li>
<li id="runkeeper"><a href="/rowers/workout/runkeeperimport/">RunKeeper</a></li>
<li id="sporttracks"><a href="/rowers/workout/sporttracksimport/">SportTracks</a></li> <li id="sporttracks"><a href="/rowers/workout/sporttracksimport/">SportTracks</a></li>
<li id="polar"><a href="/rowers/workout/polarimport/">Polar</a></li> <li id="polar"><a href="/rowers/workout/polarimport/">Polar</a></li>
<li id="rp3"><a href="/rowers/workout/rp3import/">RP3</a></li> <li id="rp3"><a href="/rowers/workout/rp3import/">RP3</a></li>

View File

@@ -29,9 +29,6 @@
{% if rower.stravatoken is not None and rower.stravatoken != '' %} {% if rower.stravatoken is not None and rower.stravatoken != '' %}
Strava, Strava,
{% endif %} {% endif %}
{% if rower.runkeepertoken is not None and rower.runkeepertoken != '' %}
Runkeeper,
{% endif %}
{% if rower.rp3token is not None and rower.rp3token != '' %} {% if rower.rp3token is not None and rower.rp3token != '' %}
RP3 RP3
{% endif %} {% endif %}
@@ -76,7 +73,6 @@
<p><a href="/rowers/me/c2authorize/"><img src="/static/img/blueC2logo.png" alt="connect with Concept2" width="120"></a></p> <p><a href="/rowers/me/c2authorize/"><img src="/static/img/blueC2logo.png" alt="connect with Concept2" width="120"></a></p>
<p><a href="/rowers/me/nkauthorize/"><img src="/static/img/NKLiNKLogbook.png" alt="connect with NK Logbook" width="120"></a></p> <p><a href="/rowers/me/nkauthorize/"><img src="/static/img/NKLiNKLogbook.png" alt="connect with NK Logbook" width="120"></a></p>
<p><a href="/rowers/me/sporttracksauthorize/"><img src="/static/img/sporttracks-button.png" alt="connect with SportTracks" width="120"></a></p> <p><a href="/rowers/me/sporttracksauthorize/"><img src="/static/img/sporttracks-button.png" alt="connect with SportTracks" width="120"></a></p>
<p><a href="/rowers/me/runkeeperauthorize/"><img src="/static/img/rk-logo.png" alt="connect with RunKeeper" width="120"></a></p>
<p><a href="/rowers/me/polarauthorize/"><img src="/static/img/Polar_connectwith_btn_white.png" <p><a href="/rowers/me/polarauthorize/"><img src="/static/img/Polar_connectwith_btn_white.png"
alt="connect with Polar" width="130"></a></p> alt="connect with Polar" width="130"></a></p>
<p><a href="/rowers/me/tpauthorize/"><img src="/static/img/TP_logo_horz_2_color.png" <p><a href="/rowers/me/tpauthorize/"><img src="/static/img/TP_logo_horz_2_color.png"

View File

@@ -19,9 +19,8 @@ from rowers.plannedsessions import (
race_can_register, race_can_submit,race_rower_status race_can_register, race_can_submit,race_rower_status
) )
from rowers import c2stuff, runkeeperstuff from rowers import c2stuff
from rowers.c2stuff import c2_open from rowers.c2stuff import c2_open
from rowers.runkeeperstuff import runkeeper_open
from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispromember from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispromember
from rowers.mytypes import ( from rowers.mytypes import (
otwtypes,adaptivetypes,sexcategories,weightcategories,workouttypes, otwtypes,adaptivetypes,sexcategories,weightcategories,workouttypes,
@@ -453,16 +452,6 @@ def currency(word):
return '{amount:.2f}'.format(amount=amount) return '{amount:.2f}'.format(amount=amount)
@register.filter
def rkuserid(user):
try:
thetoken = runkeeper_open(user)
except NoTokenError: # pragma: no cover
return 0
rkuserid = runkeeperstuff.get_userid(thetoken)
return rkuserid
@register.filter @register.filter
def courselength(course): # pragma: no cover def courselength(course): # pragma: no cover

View File

@@ -62,7 +62,6 @@ from mock import Mock, patch
import pandas as pd import pandas as pd
import rowers.c2stuff as c2stuff import rowers.c2stuff as c2stuff
import rowers.sporttracksstuff as sporttracksstuff import rowers.sporttracksstuff as sporttracksstuff
import rowers.runkeeperstuff as runkeeperstuff
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy

View File

@@ -313,8 +313,10 @@ class C2Objects(DjangoTestCase):
response = self.c.get('/rowers/workout/c2import/12/',follow=True) response = self.c.get('/rowers/workout/c2import/12/',follow=True)
expected_url = reverse('workout_c2import_view')
self.assertRedirects(response, self.assertRedirects(response,
expected_url='/rowers/workout/'+encoded2+'/edit/', expected_url=expected_url,
status_code=302,target_status_code=200) status_code=302,target_status_code=200)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@@ -485,13 +487,10 @@ class C2ObjectsTokenExpired(DjangoTestCase):
@patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.create_engine')
def test_c2_import(self, mock_get, mocked_sqlalchemy): def test_c2_import(self, mock_get, mocked_sqlalchemy):
response = self.c.get('/rowers/workout/c2import/12/',follow=True) response = self.c.get('/rowers/workout/c2import/12/')
self.assertRedirects(response,
expected_url='/rowers/list-workouts/',
status_code=302,target_status_code=200)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 302)
#@pytest.mark.django_db #@pytest.mark.django_db
@override_settings(TESTING=True) @override_settings(TESTING=True)
@@ -605,8 +604,10 @@ class NKObjects(DjangoTestCase):
result = rowers.nkstuff.rower_nk_token_refresh(self.u) result = rowers.nkstuff.rower_nk_token_refresh(self.u)
response = self.c.get('/rowers/workout/nkimport/469',follow=True) response = self.c.get('/rowers/workout/nkimport/469',follow=True)
expected_url = reverse('workout_nkimport_view')
self.assertRedirects(response, self.assertRedirects(response,
expected_url='/rowers/workout/'+encoded1+'/edit/', expected_url=expected_url,
status_code=301,target_status_code=200) status_code=301,target_status_code=200)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@@ -626,8 +627,10 @@ class NKObjects(DjangoTestCase):
result = rowers.nkstuff.rower_nk_token_refresh(self.u) result = rowers.nkstuff.rower_nk_token_refresh(self.u)
response = self.c.get('/rowers/workout/nkimport/404',follow=True) response = self.c.get('/rowers/workout/nkimport/404',follow=True)
expected_url = reverse('workout_nkimport_view')
self.assertRedirects(response, self.assertRedirects(response,
expected_url='/rowers/workout/'+encoded1+'/edit/', expected_url=expected_url,
status_code=301,target_status_code=200) status_code=301,target_status_code=200)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@@ -889,9 +892,10 @@ class StravaObjects(DjangoTestCase):
mocked_getsmallrowdata_db): mocked_getsmallrowdata_db):
response = self.c.get('/rowers/workout/stravaimport/12',follow=True) response = self.c.get('/rowers/workout/stravaimport/12',follow=True)
expected_url = reverse('workout_stravaimport_view')
self.assertRedirects(response, self.assertRedirects(response,
expected_url='/rowers/workout/'+encoded2+'/edit/', expected_url=expected_url,
status_code=301,target_status_code=200) status_code=301,target_status_code=200)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@@ -1014,8 +1018,7 @@ class STObjects(DjangoTestCase):
response = self.c.get('/rowers/workout/sporttracksimport/13/',follow=True) response = self.c.get('/rowers/workout/sporttracksimport/13/',follow=True)
expected_url = reverse('workout_edit_view', expected_url = '/rowers/workout/sporttracksimport/'
kwargs = {'id':encoder.encode_hex(2)})
self.assertRedirects(response, self.assertRedirects(response,
expected_url=expected_url, expected_url=expected_url,
@@ -1056,97 +1059,6 @@ class STObjects(DjangoTestCase):
res = add_workout_from_data(self.u,1,data,data) res = add_workout_from_data(self.u,1,data,data)
#@pytest.mark.django_db
@override_settings(TESTING=True)
class RunKeeperObjects(DjangoTestCase):
def setUp(self):
self.c = Client()
self.u = User.objects.create_user('john',
'sander@ds.ds',
'koeinsloot')
self.u.first_name = 'John'
self.u.last_name = 'Sander'
self.u.save()
self.r = Rower.objects.create(user=self.u,gdproptin=True,surveydone=True,
gdproptindate=timezone.now()
)
self.r.runkeepertoken = '12'
self.r.save()
self.c.login(username='john',password='koeinsloot')
self.nu = datetime.datetime.now()
filename = 'rowers/tests/testdata/testdata.csv'
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
hrut1=self.r.ut1,hrat=self.r.at,
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
row = rdata(csvfile=filename,rower=rr)
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
hours = int(totaltime/3600.)
minutes = int((totaltime - 3600.*hours)/60.)
seconds = int(totaltime - 3600.*hours - 60.*minutes)
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
self.w = Workout.objects.create(
name='testworkout',workouttype='water',
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
startdatetime=row.rowdatetime,
duration=duration,distance=totaldist,
csvfilename=filename
)
@patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests)
def test_runkeeper_callback(self, mock_post):
response = self.c.get('/runkeeper_callback?code=dsdoij232s',follow=True)
self.assertEqual(response.status_code, 200)
@patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests)
@patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests)
def test_runkeeper_upload(self, mock_get, mock_post):
response = self.c.get('/rowers/workout/'+encoded1+'/runkeeperuploadw/')
self.assertRedirects(response,
expected_url = '/rowers/workout/'+encoded1+'/edit/',
status_code=302,target_status_code=200)
self.assertEqual(response.url, '/rowers/workout/'+encoded1+'/edit/')
self.assertEqual(response.status_code, 302)
@patch('rowers.runkeeperstuff.requests.get', side_effect=mocked_requests)
def test_runkeeper_list(self, mock_get):
response = self.c.get('/rowers/workout/runkeeperimport',follow=True)
self.assertEqual(response.status_code,200)
@patch('rowers.imports.requests.get', side_effect=mocked_requests)
def test_runkeeper_import(self, mock_get):
response = self.c.get('/rowers/workout/runkeeperimport/12/',follow=True)
self.assertRedirects(response,
expected_url='/rowers/workout/'+encoded2+'/edit/',
status_code=302,target_status_code=200)
self.assertEqual(response.status_code, 200)
#@pytest.mark.django_db #@pytest.mark.django_db

View File

@@ -99,7 +99,6 @@ class TraverseLinksTest(TestCase):
'.*authorize.*', '.*authorize.*',
'.*youtu.*', '.*youtu.*',
'.*earth.*', '.*earth.*',
'.*runkeeper.*',
'.*c2list.*', '.*c2list.*',
'.*stravaimport.*', '.*stravaimport.*',
'.*performancephones.*', '.*performancephones.*',

View File

@@ -124,7 +124,6 @@ def matchsync(line):
tester3 = tester+'(.*)((tp)|(trainingpeaks))' tester3 = tester+'(.*)((tp)|(trainingpeaks))'
tester4 = tester+'(.*)(strava)' tester4 = tester+'(.*)(strava)'
tester5 = tester+'(.*)((st)|(sporttracks))' tester5 = tester+'(.*)((st)|(sporttracks))'
tester6 = tester+'(.*)((rk)|(runkeeper))'
tester = re.compile(tester) tester = re.compile(tester)
@@ -134,7 +133,6 @@ def matchsync(line):
('upload_totp',re.compile(tester3)), ('upload_totp',re.compile(tester3)),
('upload_to_Strava',re.compile(tester4)), ('upload_to_Strava',re.compile(tester4)),
('upload_to_SportTracks',re.compile(tester5)), ('upload_to_SportTracks',re.compile(tester5)),
('upload_to_RunKeeper',re.compile(tester6)),
('upload_to_MapMyFitness',re.compile(tester7)), ('upload_to_MapMyFitness',re.compile(tester7)),
] ]
for t in testers: for t in testers:
@@ -259,8 +257,6 @@ def getsyncoptions(uploadoptions,values): # pragma: no cover
uploadoptions['upload_to_Strava'] = True uploadoptions['upload_to_Strava'] = True
if v in ['st','sporttracks']: if v in ['st','sporttracks']:
uploadoptions['upload_to_SportTracks'] = True uploadoptions['upload_to_SportTracks'] = True
if v in ['rk','runkeeper']:
uploadoptions['upload_to_RunKeeper'] = True
except AttributeError: except AttributeError:
pass pass
@@ -487,7 +483,6 @@ def make_plot(r,w,f1,f2,plottype,title,imagename='',plotnr=0):
import rowers.c2stuff as c2stuff import rowers.c2stuff as c2stuff
import rowers.stravastuff as stravastuff import rowers.stravastuff as stravastuff
import rowers.sporttracksstuff as sporttracksstuff import rowers.sporttracksstuff as sporttracksstuff
import rowers.runkeeperstuff as runkeeperstuff
import rowers.tpstuff as tpstuff import rowers.tpstuff as tpstuff
@@ -641,16 +636,6 @@ def do_sync(w,options, quick=False):
id = 0 id = 0
if ('upload_to_RunKeeper' in options and options['upload_to_RunKeeper']) or (w.user.runkeeper_auto_export): # pragma: no cover
try:
message,id = runkeeperstuff.workout_runkeeper_upload(
w.user.user,w,asynchron=True,
)
except NoTokenError:
message = "Please connect to Runkeeper first"
id = 0
if ('upload_to_TrainingPeaks' in options and options['upload_to_TrainingPeaks']) or (w.user.trainingpeaks_auto_export): # pragma: no cover if ('upload_to_TrainingPeaks' in options and options['upload_to_TrainingPeaks']) or (w.user.trainingpeaks_auto_export): # pragma: no cover
try: try:

View File

@@ -508,13 +508,10 @@ urlpatterns = [
re_path(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all,name='workout_getsporttracksworkout_all'), re_path(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all,name='workout_getsporttracksworkout_all'),
re_path(r'^workout/polarimport/$',views.workout_polarimport_view,name='workout_polarimport_view'), re_path(r'^workout/polarimport/$',views.workout_polarimport_view,name='workout_polarimport_view'),
re_path(r'^workout/polarimport/user/(?P<userid>\d+)/',views.workout_polarimport_view,name='workout_polarimport_view'), re_path(r'^workout/polarimport/user/(?P<userid>\d+)/',views.workout_polarimport_view,name='workout_polarimport_view'),
re_path(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view,name='workout_runkeeperimport_view'),
re_path(r'^workout/runkeeperimport/user/(?P<userid>\d+)/$',views.workout_runkeeperimport_view,name='workout_runkeeperimport_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/c2uploadw/$',views.workout_c2_upload_view,name='workout_c2_upload_view'), re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/c2uploadw/$',views.workout_c2_upload_view,name='workout_c2_upload_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/stravauploadw/$',views.workout_strava_upload_view,name='workout_strava_upload_view'), re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/stravauploadw/$',views.workout_strava_upload_view,name='workout_strava_upload_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/recalcsummary/$',views.workout_recalcsummary_view,name='workout_recalcsummary_view'), re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/recalcsummary/$',views.workout_recalcsummary_view,name='workout_recalcsummary_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/sporttracksuploadw/$',views.workout_sporttracks_upload_view,name='workout_sporttracks_upload_view'), re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/sporttracksuploadw/$',views.workout_sporttracks_upload_view,name='workout_sporttracks_upload_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/runkeeperuploadw/$',views.workout_runkeeper_upload_view,name='workout_runkeeper_upload_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/tpuploadw/$',views.workout_tp_upload_view,name='workout_tp_upload_view'), re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/tpuploadw/$',views.workout_tp_upload_view,name='workout_tp_upload_view'),
re_path(r'^multi-compare/workout/(?P<id>\b[0-9A-Fa-f]+\b)/user/(?P<userid>\d+)/$',views.multi_compare_view, re_path(r'^multi-compare/workout/(?P<id>\b[0-9A-Fa-f]+\b)/user/(?P<userid>\d+)/$',views.multi_compare_view,
name='multi_compare_view'), name='multi_compare_view'),
@@ -599,7 +596,6 @@ urlpatterns = [
re_path(r'^me/sporttracksauthorize/$',views.rower_sporttracks_authorize,name='rower_sporttracks_authorize'), re_path(r'^me/sporttracksauthorize/$',views.rower_sporttracks_authorize,name='rower_sporttracks_authorize'),
re_path(r'^me/tpauthorize/$',views.rower_tp_authorize,name='rower_tp_authorize'), re_path(r'^me/tpauthorize/$',views.rower_tp_authorize,name='rower_tp_authorize'),
re_path(r'^me/rp3authorize/$',views.rower_rp3_authorize,name='rower_rp3_authorize'), re_path(r'^me/rp3authorize/$',views.rower_rp3_authorize,name='rower_rp3_authorize'),
re_path(r'^me/runkeeperauthorize/$',views.rower_runkeeper_authorize,name='rower_runkeeper_authorize'),
re_path(r'^me/sporttracksrefresh/$',views.rower_sporttracks_token_refresh,name='rower_sporttracks_token_refresh'), re_path(r'^me/sporttracksrefresh/$',views.rower_sporttracks_token_refresh,name='rower_sporttracks_token_refresh'),
re_path(r'^me/tprefresh/$',views.rower_tp_token_refresh,name='rower_tp_token_refresh'), re_path(r'^me/tprefresh/$',views.rower_tp_token_refresh,name='rower_tp_token_refresh'),
re_path(r'^me/c2refresh/$',views.rower_c2_token_refresh,name='rower_c2_token_refresh'), re_path(r'^me/c2refresh/$',views.rower_c2_token_refresh,name='rower_c2_token_refresh'),

View File

@@ -15,7 +15,7 @@ import uuid
import datetime import datetime
import json import json
import time
from fitparse import FitFile from fitparse import FitFile
from django.conf import settings from django.conf import settings

View File

@@ -225,67 +225,6 @@ def workout_c2_upload_view(request,id=0):
return response return response
# Upload workout to RunKeeper
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_runkeeper_upload_view(request,id=0):
message = ""
w = get_workout(id)
r = w.user
try:
thetoken = runkeeper_open(r.user)
except NoTokenError: # pragma: no cover
return HttpResponseRedirect("/rowers/me/runkeeperauthorize/")
# ready to upload. Hurray
data = runkeeperstuff.createrunkeeperworkoutdata(w)
if not data: # pragma: no cover
message = "Data error"
messages.error(request,message)
url = reverse(r.defaultlandingpage,
kwargs = {
'id':id,
})
return HttpResponseRedirect(url)
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json',
'Content-Length':'nnn'}
url = "https://api.runkeeper.com/fitnessActivities"
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
# check for duplicate error first
if (response.status_code == 409 ): # pragma: no cover # pragma: no cover
message = "Duplicate error"
messages.error(request,message)
w.uploadedtorunkeeper = -1
w.save()
elif (response.status_code == 201 or response.status_code==200):
runkeeperid = runkeeperstuff.getidfromresponse(response)
w.uploadedtorunkeeper = runkeeperid
w.save()
url = reverse('workout_edit_view',
kwargs={'id':encoder.encode_hex(w.id)})
return HttpResponseRedirect(url)
else: # pragma: no cover
s = response
message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text)
messages.error(request,message)
url = reverse(r.defaultlandingpage,
kwargs = {
'id':encoder.encode_hex(w.id),
}) # pragma: no cover
return HttpResponseRedirect(url) # pragma: no cover
# Upload workout to SportTracks # Upload workout to SportTracks
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid) @permission_required('workout.change_workout',fn=get_workout_by_opaqueid)
@@ -384,6 +323,7 @@ def rower_c2_authorize(request): # pragma: no cover
"redirect_uri": C2_REDIRECT_URI} "redirect_uri": C2_REDIRECT_URI}
url = "http://log.concept2.com/oauth/authorize?"+ urllib.parse.urlencode(params) url = "http://log.concept2.com/oauth/authorize?"+ urllib.parse.urlencode(params)
url += "&scope="+scope url += "&scope="+scope
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
# Garmin authorization # Garmin authorization
@@ -429,23 +369,6 @@ def rower_polar_authorize(request): # pragma: no cover
# Runkeeper authorization
@login_required()
def rower_runkeeper_authorize(request): # pragma: no cover
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
state = str(uuid4())
params = {"client_id": RUNKEEPER_CLIENT_ID,
"response_type": "code",
"state": state,
"redirect_uri": RUNKEEPER_REDIRECT_URI}
url = "https://runkeeper.com/apps/authorize?"+ urllib.parse.urlencode(params)
return HttpResponseRedirect(url)
# SportTracks Authorization # SportTracks Authorization
@login_required() @login_required()
@@ -923,31 +846,6 @@ def rower_process_stravacallback(request):
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
# Process Runkeeper callback
@login_required()
def rower_process_runkeepercallback(request):
code = request.GET['code']
res = runkeeperstuff.get_token(code)
access_token = res[0]
if access_token == 0:# pragma: no cover
messages.error(request,"Something went wrong importing the token")
url = reverse('workouts_view')
return HttpResponseRedirect(url)
r = getrower(request.user)
r.runkeepertoken = access_token
r.save()
successmessage = "Tokens stored. Good to go. Please check your import/export settings"
messages.info(request,successmessage)
url = reverse('rower_exportsettings_view')
return HttpResponseRedirect(url)
# Process SportTracks callback # Process SportTracks callback
@@ -1498,61 +1396,6 @@ def garmin_details_view(request):
return HttpResponse(status=200) return HttpResponse(status=200)
# The page where you select which RunKeeper workout to import
@login_required()
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
def workout_runkeeperimport_view(request,message="",userid=0):
res = runkeeperstuff.get_runkeeper_workout_list(request.user)
if (res.status_code != 200):
if (res.status_code == 401):
r = getrower(request.user)
if (r.runkeepertoken == '') or (r.runkeepertoken is None):
s = "Token doesn't exist. Need to authorize"
return HttpResponseRedirect("/rowers/me/runkeeperauthorize/")
message = "Something went wrong in workout_runkeeperimport_view" # pragma: no cover
messages.error(request,message) # pragma: no cover
if settings.DEBUG: # pragma: no cover
return HttpResponse(res)
else: # pragma: no cover
url = reverse('workouts_view')
return HttpResponseRedirect(url)
workouts = []
for item in res.json()['items']:
d = int(float(item['total_distance']))
i = getidfromuri(item['uri'])
ttot = str(datetime.timedelta(seconds=int(float(item['duration']))))
s = item['start_time']
r = item['type']
keys = ['id','distance','duration','starttime','type']
values = [i,d,ttot,s,r]
res = dict(zip(keys,values))
workouts.append(res)
breadcrumbs = [
{
'url':'/rowers/list-workouts/',
'name':'Workouts'
},
{
'url':reverse('workout_runkeeperimport_view'),
'name':'Runkeeper'
}
]
r = getrower(request.user)
return render(request,'runkeeper_list_import.html',
{'workouts':workouts,
'rower':r,
'active':'nav-workouts',
'breadcrumbs':breadcrumbs,
'teams':get_my_teams(request.user),
})
return HttpResponse(res) # pragma: no cover
# the page where you select which Polar workout to Import # the page where you select which Polar workout to Import
@@ -1853,18 +1696,26 @@ importlistviews = {
'strava':'workout_stravaimport_view', 'strava':'workout_stravaimport_view',
'polar':'workout_polarimport_view', 'polar':'workout_polarimport_view',
'ownapi':'workout_view', 'ownapi':'workout_view',
'runkeeper':'workout_runkeeperimport_view',
'sporttracks':'workout_sporttracksimport_view', 'sporttracks':'workout_sporttracksimport_view',
'trainingpeaks':'workout_view', 'trainingpeaks':'workout_view',
'nk':'workout_nkimport_view', 'nk':'workout_nkimport_view',
} }
importauthorizeviews = {
'c2':'rower_c2_authorize',
'strava':'rower_strava_authorize',
'polar':'rower_polar_authorize',
'ownapi':'workout_view',
'sporttracks':'rower_sporttracks_authorize',
'trainingpeaks':'rower_tp_authorize',
'nk':'rower_nk_authorize',
}
importsources = { importsources = {
'c2':c2stuff, 'c2':c2stuff,
'strava':stravastuff, 'strava':stravastuff,
'polar':polarstuff, 'polar':polarstuff,
'ownapi':ownapistuff, 'ownapi':ownapistuff,
'runkeeper':runkeeperstuff,
'sporttracks':sporttracksstuff, 'sporttracks':sporttracksstuff,
'trainingpeaks':tpstuff, 'trainingpeaks':tpstuff,
'nk':nkstuff, 'nk':nkstuff,
@@ -1894,8 +1745,12 @@ def workout_getrp3importview(request,externalid):
@login_required() @login_required()
def workout_getimportview(request,externalid,source = 'c2',do_async=True): def workout_getimportview(request,externalid,source = 'c2',do_async=True):
result = importsources[source].get_workout(request.user,externalid, try:
do_async=do_async) result = importsources[source].get_workout(request.user,externalid,
do_async=do_async)
except NoTokenError:
return HttpResponseRedirect(reverse(importauthorizeviews[source]))
if result: # pragma: no cover if result: # pragma: no cover
messages.info(request,"Your workout will be imported in the background") messages.info(request,"Your workout will be imported in the background")
@@ -1919,14 +1774,11 @@ def workout_getsporttracksworkout_all(request):
]) ])
newids = [stid for stid in stids if not stid in knownstids] newids = [stid for stid in stids if not stid in knownstids]
for sporttracksid in newids: for sporttracksid in newids:
data,strokedata = sporttracksstuff.get_workout( id = sporttracksstuff.get_workout(
request.user,sporttracksid) request.user,sporttracksid)
id,message = sporttracksstuff.add_workout_from_data(
request.user,sporttracksid,data,strokedata
)
if id==0: # pragma: no cover if id==0: # pragma: no cover
messages.error(request,message) messages.error(request,"Something went wrong with workout {id}".format(id=sporttracksid))
else: else:
w = Workout.objects.get(id=id) w = Workout.objects.get(id=id)

View File

@@ -158,7 +158,6 @@ import rowers.nkstuff as nkstuff
from rowers.c2stuff import c2_open from rowers.c2stuff import c2_open
from rowers.nkstuff import nk_open from rowers.nkstuff import nk_open
from rowers.rp3stuff import rp3_open from rowers.rp3stuff import rp3_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
from iso8601 import ParseError from iso8601 import ParseError
@@ -170,7 +169,6 @@ import rowers.sporttracksstuff as sporttracksstuff
import rowers.tpstuff as tpstuff import rowers.tpstuff as tpstuff
import rowers.runkeeperstuff as runkeeperstuff
import rowers.rp3stuff as rp3stuff import rowers.rp3stuff as rp3stuff
import rowers.ownapistuff as ownapistuff import rowers.ownapistuff as ownapistuff
from rowers.ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI from rowers.ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI
@@ -180,7 +178,6 @@ from rowsandall_app.settings import (
POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET, POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET,
SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI,
SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_SECRET,
RUNKEEPER_CLIENT_ID,RUNKEEPER_REDIRECT_URI,RUNKEEPER_CLIENT_SECRET,
TP_CLIENT_ID,TP_REDIRECT_URI,TP_CLIENT_KEY,TP_CLIENT_SECRET, TP_CLIENT_ID,TP_REDIRECT_URI,TP_CLIENT_KEY,TP_CLIENT_SECRET,
RP3_CLIENT_ID,RP3_REDIRECT_URI,RP3_CLIENT_KEY,RP3_CLIENT_SECRET, RP3_CLIENT_ID,RP3_REDIRECT_URI,RP3_CLIENT_KEY,RP3_CLIENT_SECRET,
BRAINTREE_MERCHANT_ID,BRAINTREE_PUBLIC_KEY,BRAINTREE_PRIVATE_KEY, BRAINTREE_MERCHANT_ID,BRAINTREE_PUBLIC_KEY,BRAINTREE_PRIVATE_KEY,

View File

@@ -4864,8 +4864,6 @@ def workout_upload_api(request):
upload_to_c2 = optionsform.cleaned_data['upload_to_C2'] upload_to_c2 = optionsform.cleaned_data['upload_to_C2']
upload_to_strava = optionsform.cleaned_data['upload_to_Strava'] upload_to_strava = optionsform.cleaned_data['upload_to_Strava']
upload_to_st = optionsform.cleaned_data['upload_to_SportTracks'] upload_to_st = optionsform.cleaned_data['upload_to_SportTracks']
upload_to_rk = optionsform.cleaned_data['upload_to_RunKeeper']
upload_to_ua = optionsform.cleaned_data['upload_to_MapMyFitness']
upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks'] upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks']
makeprivate = optionsform.cleaned_data['makeprivate'] makeprivate = optionsform.cleaned_data['makeprivate']
else: # pragma: no cover else: # pragma: no cover
@@ -5042,8 +5040,6 @@ def workout_upload_view(request,
upload_to_c2 = uploadoptions.get('upload_to_C2',False) upload_to_c2 = uploadoptions.get('upload_to_C2',False)
upload_to_strava = uploadoptions.get('upload_to_Strava',False) upload_to_strava = uploadoptions.get('upload_to_Strava',False)
upload_to_st = uploadoptions.get('upload_to_SportTracks',False) upload_to_st = uploadoptions.get('upload_to_SportTracks',False)
upload_to_rk = uploadoptions.get('upload_to_RunKeeper',False)
upload_to_ua = uploadoptions.get('upload_to_MapMyFitness',False)
upload_to_tp = uploadoptions.get('upload_to_TrainingPeaks',False) upload_to_tp = uploadoptions.get('upload_to_TrainingPeaks',False)
response = {} response = {}
@@ -5093,8 +5089,6 @@ def workout_upload_view(request,
upload_to_c2 = optionsform.cleaned_data['upload_to_C2'] upload_to_c2 = optionsform.cleaned_data['upload_to_C2']
upload_to_strava = optionsform.cleaned_data['upload_to_Strava'] upload_to_strava = optionsform.cleaned_data['upload_to_Strava']
upload_to_st = optionsform.cleaned_data['upload_to_SportTracks'] upload_to_st = optionsform.cleaned_data['upload_to_SportTracks']
upload_to_rk = optionsform.cleaned_data['upload_to_RunKeeper']
upload_to_ua = optionsform.cleaned_data['upload_to_MapMyFitness']
upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks'] upload_to_tp = optionsform.cleaned_data['upload_to_TrainingPeaks']
makeprivate = optionsform.cleaned_data['makeprivate'] makeprivate = optionsform.cleaned_data['makeprivate']
landingpage = optionsform.cleaned_data['landingpage'] landingpage = optionsform.cleaned_data['landingpage']
@@ -5112,8 +5106,6 @@ def workout_upload_view(request,
'upload_to_C2':upload_to_c2, 'upload_to_C2':upload_to_c2,
'upload_to_Strava':upload_to_strava, 'upload_to_Strava':upload_to_strava,
'upload_to_SportTracks':upload_to_st, 'upload_to_SportTracks':upload_to_st,
'upload_to_RunKeeper':upload_to_rk,
'upload_to_MapMyFitness':upload_to_ua,
'upload_to_TrainingPeaks':upload_to_tp, 'upload_to_TrainingPeaks':upload_to_tp,
'landingpage':landingpage, 'landingpage':landingpage,
'boattype': boattype, 'boattype': boattype,
@@ -5255,20 +5247,6 @@ def workout_upload_view(request,
else: else:
messages.error(request,message) messages.error(request,message)
if (upload_to_rk): # pragma: no cover
try:
message,id = runkeeperstuff.workout_runkeeper_upload(
request.user,w
)
except NoTokenError:
message = "Please connect to Runkeeper first"
id = 0
if id>1:
messages.info(request,message)
else:
messages.error(request,message)
if (upload_to_tp): # pragma: no cover if (upload_to_tp): # pragma: no cover
try: try:
@@ -5447,14 +5425,9 @@ def workout_upload_view(request,
if r.sporttracks_auto_export and ispromember(r.user): # pragma: no cover if r.sporttracks_auto_export and ispromember(r.user): # pragma: no cover
uploadoptions['upload_to_SportTracks'] = True uploadoptions['upload_to_SportTracks'] = True
if r.runkeeper_auto_export and ispromember(r.user): # pragma: no cover
uploadoptions['upload_to_RunKeeper'] = True
if r.trainingpeaks_auto_export and ispromember(r.user): # pragma: no cover if r.trainingpeaks_auto_export and ispromember(r.user): # pragma: no cover
uploadoptions['upload_to_TrainingPeaks'] = True uploadoptions['upload_to_TrainingPeaks'] = True
if r.mapmyfitness_auto_export and ispromember(r.user): # pragma: no cover
uploadoptions['upload_to_MapMyFitness'] = True
form = DocumentsForm(initial=docformoptions) form = DocumentsForm(initial=docformoptions)
optionsform = UploadOptionsForm(initial=uploadoptions, optionsform = UploadOptionsForm(initial=uploadoptions,

View File

@@ -75,7 +75,6 @@ urlpatterns += [
re_path(r'^garmin\_callback',rowersviews.rower_process_garmincallback), re_path(r'^garmin\_callback',rowersviews.rower_process_garmincallback),
re_path(r'^sporttracks\_callback',rowersviews.rower_process_sporttrackscallback), re_path(r'^sporttracks\_callback',rowersviews.rower_process_sporttrackscallback),
re_path(r'^polarflowcallback',rowersviews.rower_process_polarcallback), re_path(r'^polarflowcallback',rowersviews.rower_process_polarcallback),
re_path(r'^runkeeper\_callback',rowersviews.rower_process_runkeepercallback),
re_path(r'^tp\_callback',rowersviews.rower_process_tpcallback), re_path(r'^tp\_callback',rowersviews.rower_process_tpcallback),
re_path(r'^rp3\_callback',rowersviews.rower_process_rp3callback), re_path(r'^rp3\_callback',rowersviews.rower_process_rp3callback),
re_path(r'^twitter\_callback',rowersviews.rower_process_twittercallback), re_path(r'^twitter\_callback',rowersviews.rower_process_twittercallback),