Private
Public Access
1
0

Merge branch 'release/v16.0.1'

This commit is contained in:
Sander Roosendaal
2021-04-10 12:53:38 +02:00
18 changed files with 513 additions and 376 deletions
+26 -8
View File
@@ -1853,8 +1853,15 @@ parsers = {
'nklinklogbook': NKLiNKLogbookParser, 'nklinklogbook': NKLiNKLogbookParser,
} }
def parsenonpainsled(fileformat,f2,summary,startdatetime=''): def parsenonpainsled(fileformat,f2,summary,startdatetime='',empowerfirmware=None,inboard=None,oarlength=None):
try: try:
if fileformat == 'nklinklogbook' and empowerfirmware is not None:
if inboard is not None and oarlength is not None:
row = NKLiNKLogbookParser(f2,firmware=empowerfirmware,inboard=inboard,oarlength=oarlength)
print(row,'aap')
else:
row = NKLiNKLogbookParser(f2)
else:
row = parsers[fileformat](f2) row = parsers[fileformat](f2)
if startdatetime != '': if startdatetime != '':
row.rowdatetime = arrow.get(startdatetime).datetime row.rowdatetime = arrow.get(startdatetime).datetime
@@ -1875,6 +1882,8 @@ def parsenonpainsled(fileformat,f2,summary,startdatetime=''):
summary = row.allstats() summary = row.allstats()
except ZeroDivisionError: except ZeroDivisionError:
summary = '' summary = ''
else:
fileformat = fileformat+'v'+str(empowerfirmware)
# handle FIT # handle FIT
if (fileformat == 'fit'): if (fileformat == 'fit'):
@@ -1889,13 +1898,14 @@ def parsenonpainsled(fileformat,f2,summary,startdatetime=''):
return row,hasrecognized,summary,fileformat return row,hasrecognized,summary,fileformat
def handle_nonpainsled(f2, fileformat, summary='',startdatetime=''): def handle_nonpainsled(f2, fileformat, summary='',startdatetime='',empowerfirmware=None,impeller=False):
oarlength = 2.89 oarlength = 2.89
inboard = 0.88 inboard = 0.88
hasrecognized = False hasrecognized = False
impeller = False
row,hasrecognized,summary,fileformat = parsenonpainsled(fileformat,f2,summary,startdatetime=startdatetime)
row,hasrecognized,summary,fileformat = parsenonpainsled(fileformat,f2,summary,startdatetime=startdatetime,
empowerfirmware=empowerfirmware)
# Handle c2log # Handle c2log
if (fileformat == 'c2log' or fileformat == 'rowprolog'): if (fileformat == 'c2log' or fileformat == 'rowprolog'):
@@ -1909,13 +1919,15 @@ def handle_nonpainsled(f2, fileformat, summary='',startdatetime=''):
f2 = f2[:-4] + 'o.csv' f2 = f2[:-4] + 'o.csv'
row2 = rrdata(df = row.df) row2 = rrdata(df = row.df)
if 'speedcoach2' in fileformat: if 'speedcoach2' in fileformat or 'nklinklogbook' in fileformat:
# impeller consistency # impeller consistency
impellerdata, consistent, ratio = row.impellerconsistent(threshold=0.3) impellerdata, consistent, ratio = row.impellerconsistent(threshold=0.3)
if impellerdata and consistent: if impellerdata and consistent:
impeller = True impeller = True
if impellerdata and not consistent: if impellerdata and not consistent:
row2.use_gpsdata() row2.use_gpsdata()
if impeller:
row2.use_impellerdata()
row2.write_csv(f2, gzip=True) row2.write_csv(f2, gzip=True)
@@ -1990,9 +2002,13 @@ def new_workout_from_file(r, f2,
makeprivate=False, makeprivate=False,
startdatetime='', startdatetime='',
notes='', notes='',
oarlockfirmware='',
inboard=None,
oarlength=None,
impeller=False,
uploadoptions={'boattype':'1x','workouttype':'rower'}): uploadoptions={'boattype':'1x','workouttype':'rower'}):
message = "" message = ""
impeller = False
try: try:
fileformat = get_file_type(f2) fileformat = get_file_type(f2)
except (IOError,UnicodeDecodeError): except (IOError,UnicodeDecodeError):
@@ -2009,7 +2025,7 @@ def new_workout_from_file(r, f2,
uploadoptions['fromuploadform'] = True uploadoptions['fromuploadform'] = True
bodyyaml = yaml.safe_dump(uploadoptions,default_flow_style=False) bodyyaml = yaml.safe_dump(uploadoptions,default_flow_style=False)
f_to_be_deleted = f2 f_to_be_deleted = f2
impeller = False
workoutsbox = Mailbox.objects.filter(name='workouts')[0] workoutsbox = Mailbox.objects.filter(name='workouts')[0]
msg = Message(mailbox=workoutsbox, msg = Message(mailbox=workoutsbox,
from_header=r.user.email, from_header=r.user.email,
@@ -2095,7 +2111,9 @@ def new_workout_from_file(r, f2,
f2, f2,
fileformat, fileformat,
startdatetime=startdatetime, startdatetime=startdatetime,
summary=summary summary=summary,
empowerfirmware=oarlockfirmware,
impeller=impeller,
) )
if not f2: if not f2:
message = 'Something went wrong' message = 'Something went wrong'
@@ -33,6 +33,7 @@ import rowers.polarstuff as polarstuff
import rowers.c2stuff as c2stuff import rowers.c2stuff as c2stuff
import rowers.rp3stuff as rp3stuff import rowers.rp3stuff as rp3stuff
import rowers.stravastuff as stravastuff import rowers.stravastuff as stravastuff
import rowers.nkstuff as nkstuff
from rowers.opaque import encoder from rowers.opaque import encoder
from rowers.models import User,VirtualRace,Workout from rowers.models import User,VirtualRace,Workout
@@ -213,6 +214,11 @@ class Command(BaseCommand):
if user_is_not_basic(r.user): if user_is_not_basic(r.user):
res = rp3stuff.get_rp3_workouts(r) res = rp3stuff.get_rp3_workouts(r)
rowers = Rower.objects.filter(nk_auto_import=True)
for r in rowers:
if user_is_not_basic(r.user):
res = nkstuff.get_nk_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]
attachments = MessageAttachment.objects.filter( attachments = MessageAttachment.objects.filter(
+2 -1
View File
@@ -1002,7 +1002,7 @@ class Rower(models.Model):
nkrefreshtoken = models.TextField(default='',max_length=1000, nkrefreshtoken = models.TextField(default='',max_length=1000,
blank=True,null=True) blank=True,null=True)
nk_owner_id = models.BigIntegerField(default=0) nk_owner_id = models.BigIntegerField(default=0)
nk_auto_import = models.BooleanField(default=False) nk_auto_import = models.BooleanField(default=False,verbose_name='NK LiNK auto import')
trainingpeaks_auto_export = models.BooleanField(default=False) trainingpeaks_auto_export = models.BooleanField(default=False)
@@ -3852,6 +3852,7 @@ class RowerExportForm(ModelForm):
'polar_auto_import', 'polar_auto_import',
'c2_auto_export', 'c2_auto_export',
'c2_auto_import', 'c2_auto_import',
'nk_auto_import',
'mapmyfitness_auto_export', 'mapmyfitness_auto_export',
'runkeeper_auto_export', 'runkeeper_auto_export',
'sporttracks_auto_export', 'sporttracks_auto_export',
+264
View File
@@ -0,0 +1,264 @@
import pandas as pd
import datetime
from datetime import timedelta
from uuid import uuid4
from rowsandall_app.settings import UPLOAD_SERVICE_SECRET, UPLOAD_SERVICE_URL
from rowsandall_app.settings import NK_API_LOCATION
import requests
def strfdelta(tdelta):
try:
minutes, seconds = divmod(tdelta.seconds, 60)
tenths = int(tdelta.microseconds / 1e5)
except AttributeError:
minutes, seconds = divmod(tdelta.view(np.int64), 60e9)
seconds, rest = divmod(seconds, 1e9)
tenths = int(rest / 1e8)
res = "{minutes:0>2}:{seconds:0>2}.{tenths:0>1}".format(
minutes=minutes,
seconds=seconds,
tenths=tenths,
)
return res
def add_workout_from_data(userid,nkid,data,strokedata,source='nk',splitdata=None,
workoutsource='nklinklogbook'):
csvfilename = 'media/{code}_{nkid}.csv.gz'.format(
nkid=nkid,
code = uuid4().hex[:16]
)
try:
userid=int(userid)
except TypeError:
userid = userid.id
strokedata.to_csv(csvfilename, index_label='index', compression='gzip')
title = data["name"]
speedInput = data["speedInput"]
elapsedTime = data["elapsedTime"]
totalDistanceGps = data["totalDistanceGps"]
totalDistanceImp = data["totalDistanceImp"]
intervals = data["intervals"] # add intervals
oarlockSessions = data["oarlockSessions"]
deviceId = data["deviceId"] # you could get the firmware version
totalDistance = totalDistanceGps
useImpeller = False
if speedInput:
totdalDistance = totalDistanceImp
useImpeller = True
summary = get_nk_allstats(data,strokedata)
speedInput = data['speedInput'] # 0 = GPS; 1 = Impeller
# oarlock inboard, length, boat name
if oarlockSessions:
oarlocksession = oarlockSessions[0] # should take seatIndex
boatName = oarlocksession["boatName"]
oarLength = oarlocksession["oarLength"] # cm
oarInboardLength = oarlocksession["oarInboardLength"] # cm
seatNumber = oarlocksession["seatNumber"]
try:
oarlockfirmware = oarlocksession["firmwareVersion"]
except KeyError:
oarlockfirmware = ''
else:
boatName = ''
oarLength = 289
oarInboardLength = 88
seatNumber = 1
oarlockfirmware = ''
workouttype = "water"
boattype = "1x"
uploadoptions = {
'secret': UPLOAD_SERVICE_SECRET,
'user':userid,
'file': csvfilename,
'title': title,
'workouttype': workouttype,
'boattype': boattype,
'nkid':nkid,
'inboard': oarInboardLength/100.,
'oarlength': oarLength/100.,
'summary':summary,
'oarlockfirmware':oarlockfirmware,
'elapsedTime': elapsedTime/1000., # in seconds
'totalDistance': totalDistance,
'useImpeller': useImpeller
}
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,response.text
try:
workoutid = response.json()['id']
except KeyError:
workoutid = 1
# evt update workout summary
# return
return workoutid,""
def get_nk_intervalstats(workoutdata,strokedata):
intervals = workoutdata['intervals']
separator = "|"
stri = "Workout Details\n"
stri += "#-{sep}SDist{sep}-Split-{sep}-SPace-{sep}-Pwr-{sep}-SPM--{sep}-AvgHR-{sep}DPS-\n".format(
sep=separator)
i = 0
for interval in intervals:
id = interval['id']
sdist = interval['totalDistanceGps']
avgpace = interval['avgPaceGps']/1000.
avgpacetd = timedelta(seconds=avgpace)
newpacestring = strfdelta(avgpacetd)
elapsedSeconds = interval['elapsedTime']/1000. # secs
elapsedTime = datetime.datetime.utcfromtimestamp(elapsedSeconds)
newsplitstring = "%s.%i" % (elapsedTime.strftime("%M:%S"), elapsedTime.microsecond/100000)
pwr = interval['avgPower']
avghr = interval['avgHeartRate']
spm = interval['avgStrokeRate']
dps = interval['distStrokeGps']
stri += "{i:0>2}{sep}{sdist:0>5}{sep}{split}{sep}{space}{sep} {pwr:0>3} {sep}".format(
i=i + 1,
sdist=int(float(sdist)),
split=newsplitstring,
space=newpacestring,
pwr=int(pwr),
sep=separator,
)
stri += " {spm} {sep} {avghr:0>3} {sep}{dps:0>4.1f}\n".format(
sep=separator,
avghr=avghr,
spm=spm,
dps=dps,
)
i += 1
return stri
def get_nk_summary(workoutdata,strokedata):
name = workoutdata['name']
avgpace = workoutdata['avgPaceGps']/1000. # secs
avgpacetd = timedelta(seconds=avgpace)
avgpacestring = strfdelta(avgpacetd)
elapsedSeconds = workoutdata['elapsedTime']/1000. # secs
elapsedTime = datetime.datetime.utcfromtimestamp(elapsedSeconds)
timestring = "%s.%i" % (elapsedTime.strftime("%H:%M:%S"), elapsedTime.microsecond/100000)
dist = workoutdata['totalDistanceGps']
spm = workoutdata['avgStrokeRate']
avghr = workoutdata['avgHeartRate']
avgdps = workoutdata['distStrokeGps']
maxhr = strokedata['heartRate'].max()
pwr = workoutdata['avgPower']
sep = "|"
stri1 = "Workout Summary - " + name + "\n"
stri1 += "--{sep}Total{sep}--Total---{sep}--Avg--{sep}-Avg-{sep}-Avg--{sep}-Avg-{sep}-Max-{sep}-Avg\n".format(
sep=sep)
stri1 += "--{sep}Dist-{sep}--Time----{sep}-Pace--{sep}-Pwr-{sep}-SPM--{sep}-HR--{sep}-HR--{sep}-DPS\n".format(
sep=sep)
stri1 += "--{sep}{dist:0>5.0f}{sep}".format(
sep=sep,
dist=dist,
)
stri1 += timestring + sep + avgpacestring
stri1 += "{sep}{avgpower:0>5.1f}".format(
sep=sep,
avgpower=pwr,
)
stri1 += "{sep} {avgsr:2.1f} {sep}{avghr:0>5.1f}{sep}".format(
avgsr=spm,
sep=sep,
avghr=avghr
)
stri1 += "{maxhr:0>5.1f}{sep}{avgdps:0>4.1f}\n".format(
sep=sep,
maxhr=maxhr,
avgdps=avgdps
)
return stri1
return stri1
def get_nk_allstats(data,workoutdata):
stri = get_nk_summary(data, workoutdata) + \
get_nk_intervalstats(data, workoutdata)
return stri
#def get_workout(user,nkid):
def getdict(x, seatIndex=1):
seatStrokes = pd.DataFrame(x)
try:
seatStrokes = seatStrokes.set_index('seatIndex')
return dict(seatStrokes.loc[seatIndex])
except KeyError:
pass
return {}
def strokeDataToDf(strokeData):
df = pd.DataFrame.from_dict(strokeData)
oarlockData = df['oarlockStrokes']
oarlockData = oarlockData.apply(lambda x:getdict(x, seatIndex=1))
df2 = pd.DataFrame.from_records(oarlockData.values)
#df.set_index('timestamp',inplace=True)
if not df2.empty:
#df2.set_index('timestamp',inplace=True)
df = df.merge(df2,left_index=True,right_index=True)
df = df.rename(columns={"timestamp_x":"timestamp"})
df = df.drop('oarlockStrokes',axis=1)
df.sort_values(by='timestamp',ascending=True,inplace=True)
df.fillna(inplace=True,method='ffill')
return df
+9 -97
View File
@@ -22,7 +22,7 @@ queuehigh = django_rq.get_queue('low')
from rowers.rower_rules import is_workout_user, ispromember from rowers.rower_rules import is_workout_user, ispromember
from iso8601 import ParseError from iso8601 import ParseError
from rowers.utils import myqueue,get_nk_summary, get_nk_allstats, get_nk_intervalstats,getdict from rowers.utils import myqueue
import rowers.mytypes as mytypes import rowers.mytypes as mytypes
import gzip import gzip
@@ -42,6 +42,7 @@ except ImportError:
JSONDecodeError = ValueError JSONDecodeError = ValueError
from rowers.imports import * from rowers.imports import *
from rowers.nkimportutils import *
oauth_data = { oauth_data = {
'client_id': NK_CLIENT_ID, 'client_id': NK_CLIENT_ID,
@@ -209,7 +210,7 @@ def rower_nk_token_refresh(user):
def make_authorization_url(request): def make_authorization_url(request):
return imports_make_authorization_url(oauth_data) return imports_make_authorization_url(oauth_data)
def get_nk_workout_list(user,fake=False): def get_nk_workout_list(user,fake=False,startTime=0,endTime=0):
r = Rower.objects.get(user=user) r = Rower.objects.get(user=user)
if (r.nktoken == '') or (r.nktoken is None): if (r.nktoken == '') or (r.nktoken is None):
@@ -220,10 +221,12 @@ def get_nk_workout_list(user,fake=False):
return custom_exception_handler(401,s) return custom_exception_handler(401,s)
else: else:
# ready to fetch. Hurray # ready to fetch. Hurray
if not endTime:
endTime = int(arrow.now().timestamp())*1000 endTime = int(arrow.now().timestamp())*1000
endTime = str(endTime) endTime = str(endTime)
startTime = arrow.now()-timedelta(days=30)*1000 if not startTime:
startTime = str(int(startTime.timestamp())) startTime = arrow.now()-timedelta(days=30)
startTime = str(int(startTime.timestamp())*1000)
authorizationstring = str('Bearer ' + r.nktoken) authorizationstring = str('Bearer ' + r.nktoken)
headers = {'Authorization': authorizationstring, headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal', 'user-agent': 'sanderroosendaal',
@@ -244,81 +247,6 @@ def get_nk_workout_list(user,fake=False):
# #
def add_workout_from_data(user,nkid,data,strokedata,source='nk',splitdata=None,
workoutsource='nklinklogbook'):
csvfilename = 'media/{code}_{nkid}.csv.gz'.format(
nkid=nkid,
code = uuid4().hex[:16]
)
strokedata.to_csv(csvfilename, index_label='index', compression='gzip')
userid = user.id
title = data["name"]
speedInput = data["speedInput"]
elapsedTime = data["elapsedTime"]
totalDistanceGps = data["totalDistanceGps"]
totalDistanceImp = data["totalDistanceImp"]
intervals = data["intervals"] # add intervals
oarlockSessions = data["oarlockSessions"]
deviceId = data["deviceId"] # you could get the firmware version
summary = get_nk_allstats(data,strokedata)
# oarlock inboard, length, boat name
if oarlockSessions:
oarlocksession = oarlockSessions[0] # should take seatIndex
boatName = oarlocksession["boatName"]
oarLength = oarlocksession["oarLength"] # cm
oarInboardLength = oarlocksession["oarInboardLength"] # cm
seatNumber = oarlocksession["seatNumber"]
else:
boatName = ''
oarLength = 289
oarInboardLength = 88
seatNumber = 1
workouttype = "water"
boattype = "1x"
uploadoptions = {
'secret': UPLOAD_SERVICE_SECRET,
'user':userid,
'file': csvfilename,
'title': title,
'workouttype': workouttype,
'boattype': boattype,
'nkid':nkid,
'inboard': oarInboardLength/100.,
'oarlength': oarLength/100.,
'summary':summary,
}
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,response.text
try:
workoutid = response.json()['id']
except KeyError:
workoutid = 1
# evt update workout summary
# return
return workoutid,""
def get_workout(user,nkid): def get_workout(user,nkid):
r = Rower.objects.get(user=user) r = Rower.objects.get(user=user)
if (r.nktoken == '') or (r.nktoken is None): if (r.nktoken == '') or (r.nktoken is None):
@@ -338,8 +266,6 @@ def get_workout(user,nkid):
'Content-Type': 'application/json', 'Content-Type': 'application/json',
} }
# get strokes # get strokes
url = NK_API_LOCATION+"api/v1/sessions/strokes" url = NK_API_LOCATION+"api/v1/sessions/strokes"
response = requests.get(url,headers=headers,params=params) response = requests.get(url,headers=headers,params=params)
@@ -353,22 +279,7 @@ def get_workout(user,nkid):
strokeData = jsonData[str(nkid)] strokeData = jsonData[str(nkid)]
df = pd.DataFrame.from_dict(strokeData) df = strokeDataToDf(strokeData)
oarlockData = df['oarlockStrokes']
oarlockData = oarlockData.apply(lambda x:getdict(x, seatIndex=1))
df2 = pd.DataFrame.from_records(oarlockData.values)
df.set_index('timestamp')
if not df2.empty:
df2.set_index('timestamp')
df = df.merge(df2,left_index=True,right_index=True)
df = df.rename(columns={"timestamp_x":"timestamp"})
df = df.drop('oarlockStrokes',axis=1)
df.sort_values(by='timestamp',ascending=True,inplace=True)
df.fillna(inplace=True,method='ffill')
# get workout data # get workout data
timestampbegin = df['timestamp'].min() timestampbegin = df['timestamp'].min()
@@ -379,6 +290,7 @@ def get_workout(user,nkid):
'startTime':timestampbegin-1, 'startTime':timestampbegin-1,
'endTime': timestampend+1, 'endTime': timestampend+1,
} }
response = requests.get(url, headers=headers,params=params) response = requests.get(url, headers=headers,params=params)
if response.status_code != 200: if response.status_code != 200:
+10 -70
View File
@@ -111,7 +111,10 @@ def safetimedelta(x):
siteurl = SITE_URL siteurl = SITE_URL
from rowers.utils import get_nk_summary, get_nk_allstats, get_nk_intervalstats,getdict from rowers.nkimportutils import (
get_nk_summary, get_nk_allstats, get_nk_intervalstats,getdict,strokeDataToDf,
add_workout_from_data
)
# testing task # testing task
@@ -2958,6 +2961,7 @@ def handle_rp3_async_workout(userid,rp3token,rp3id,startdatetime,max_attempts,de
@app.task @app.task
def handle_nk_async_workout(alldata,userid,nktoken,nkid,delaysec,defaulttimezone,debug=False,**kwargs): def handle_nk_async_workout(alldata,userid,nktoken,nkid,delaysec,defaulttimezone,debug=False,**kwargs):
time.sleep(delaysec) time.sleep(delaysec)
data = alldata[nkid] data = alldata[nkid]
params = { params = {
@@ -2981,22 +2985,8 @@ def handle_nk_async_workout(alldata,userid,nktoken,nkid,delaysec,defaulttimezone
jsonData = response.json() jsonData = response.json()
strokeData = jsonData[str(nkid)] strokeData = jsonData[str(nkid)]
df = pd.DataFrame.from_dict(strokeData)
oarlockData = df['oarlockStrokes']
oarlockData = oarlockData.apply(lambda x:getdict(x, seatIndex=1)) df = strokeDataToDf(strokeData)
df2 = pd.DataFrame.from_records(oarlockData.values)
df.set_index('timestamp')
if not df2.empty:
df2.set_index('timestamp')
df = df.merge(df2,left_index=True,right_index=True)
df = df.rename(columns={"timestamp_x":"timestamp"})
df = df.drop('oarlockStrokes',axis=1)
df.sort_values(by='timestamp',ascending=True,inplace=True)
df.fillna(inplace=True,method='ffill')
# get workout data # get workout data
timestampbegin = df['timestamp'].min() timestampbegin = df['timestamp'].min()
@@ -3009,60 +2999,7 @@ def handle_nk_async_workout(alldata,userid,nktoken,nkid,delaysec,defaulttimezone
df.to_csv(csvfilename, index_label='index', compression='gzip') df.to_csv(csvfilename, index_label='index', compression='gzip')
workoutid,error = add_workout_from_data(userid,nkid,data,df)
title = data["name"]
speedInput = data["speedInput"]
elapsedTime = data["elapsedTime"]
totalDistanceGps = data["totalDistanceGps"]
totalDistanceImp = data["totalDistanceImp"]
intervals = data["intervals"] # add intervals
oarlockSessions = data["oarlockSessions"]
deviceId = data["deviceId"] # you could get the firmware version
summary = get_nk_allstats(data,df)
# oarlock inboard, length, boat name
if oarlockSessions:
oarlocksession = oarlockSessions[0] # should take seatIndex
boatName = oarlocksession["boatName"]
oarLength = oarlocksession["oarLength"] # cm
oarInboardLength = oarlocksession["oarInboardLength"] # cm
seatNumber = oarlocksession["seatNumber"]
else:
boatName = ''
oarLength = 289
oarInboardLength = 88
seatNumber = 1
workouttype = "water"
boattype = "1x"
uploadoptions = {
'secret': UPLOAD_SERVICE_SECRET,
'user':userid,
'file': csvfilename,
'title': title,
'workouttype': workouttype,
'boattype': boattype,
'nkid':nkid,
'inboard': oarInboardLength/100.,
'oarlength': oarLength/100.,
'summary':summary,
}
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,response.text
try:
workoutid = response.json()['id']
except KeyError:
workoutid = 1
if debug: if debug:
engine = create_engine(database_url_debug, echo=False) engine = create_engine(database_url_debug, echo=False)
@@ -3081,9 +3018,12 @@ def handle_nk_async_workout(alldata,userid,nktoken,nkid,delaysec,defaulttimezone
conn.close() conn.close()
parkedids = [] parkedids = []
try:
with open('nkblocked.json','r') as nkblocked: with open('nkblocked.json','r') as nkblocked:
jsondata = json.load(nkblocked) jsondata = json.load(nkblocked)
parkedids = jsondata['ids'] parkedids = jsondata['ids']
except FileNotFoundError:
pass
newparkedids = [id for id in parkedids if id != newnkid] newparkedids = [id for id in parkedids if id != newnkid]
with open('nkblocked.json','wt') as nkblocked: with open('nkblocked.json','wt') as nkblocked:
+1 -1
View File
@@ -335,7 +335,7 @@
<i class="fas fa-eraser fa-fw"></i>&nbsp;Remove Power Data <i class="fas fa-eraser fa-fw"></i>&nbsp;Remove Power Data
</a> </a>
</li> </li>
{% if 'speedcoach2' in workout.workoutsource %} {% if 'speedcoach2' in workout.workoutsource or 'nklinklogbook' in workout.workoutsource %}
<li id="advanced-usegps"> <li id="advanced-usegps">
<a href="/rowers/workout/{{ workout.id|encode }}/otwusegps/"> <a href="/rowers/workout/{{ workout.id|encode }}/otwusegps/">
<i class="fas fa-satellite"></i> <i class="fas fa-satellite"></i>
+12 -2
View File
@@ -623,6 +623,12 @@ def mocked_requests(*args, **kwargs):
with open('rowers/tests/testdata/nk_list.json','r') as infile: with open('rowers/tests/testdata/nk_list.json','r') as infile:
nkworkoutlist = json.load(infile) nkworkoutlist = json.load(infile)
with open('rowers/tests/testdata/example-session-strokes-with-impeller-data.json','r') as infile:
nkimpellerstrokedata = json.load(infile)
with open('rowers/tests/testdata/example-session-with-impeller-data.json','r') as infile:
nkimpellerworkoutlist = json.load(infile)
polar_json = { polar_json = {
'available-user-data': [] 'available-user-data': []
} }
@@ -960,10 +966,14 @@ def mocked_requests(*args, **kwargs):
} }
return MockResponse(json_data,200) return MockResponse(json_data,200)
if nkstrokestester.match(args[0]): if nkstrokestester.match(args[0]):
params = kwargs.pop('params',{})
if 'sessionIds' in params and params['sessionIds'] == '404':
return MockResponse(nkimpellerstrokedata, 200)
return MockResponse(nkstrokedata,200) return MockResponse(nkstrokedata,200)
if nkworkoutlisttester.match(args[0]): if nkworkoutlisttester.match(args[0]):
params = kwargs.pop('params',{})
if 'startTime' in params and params['startTime'] == 1267136372998:
return MockResponse(nkimpellerworkoutlist,200)
return MockResponse(nkworkoutlist,200) return MockResponse(nkworkoutlist,200)
+64 -1
View File
@@ -424,9 +424,44 @@ class NKObjects(DjangoTestCase):
self.assertEqual(response.status_code,200) self.assertEqual(response.status_code,200)
@patch('rowers.nkimportutils.requests.session', side_effect=mocked_session)
@patch('rowers.tasks.requests.get', side_effects=mocked_requests)
def test_handle_nk_get_workouts(self, mocked_session, mock_get):
with open('rowers/tests/testdata/nk_list.json','r') as f:
data = json.load(f)
with open('rowers/tests/testdata/nk_strokes.json','r') as f:
strokeData = json.load(f)
alldata = {}
for item in data:
alldata[item['id']] = item
result = rowers.nkstuff.rower_nk_token_refresh(self.u)
res = tasks.handle_nk_async_workout(
alldata,self.r.user.id,self.r.nktoken,469,0,'UTC'
)
@patch('rowers.nkstuff.requests.get', side_effect=mocked_requests) @patch('rowers.nkstuff.requests.get', side_effect=mocked_requests)
@patch('rowers.nkstuff.requests.post', side_effect=mocked_requests) @patch('rowers.nkstuff.requests.post', side_effect=mocked_requests)
@patch('rowers.nkstuff.requests.session', side_effect=mocked_session) def test_nk_get_workouts(self, mock_get, mockpost):
result = rowers.nkstuff.nk_open(self.u)
self.assertEqual(result,"TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq")
response = self.c.get('/rowers/workout/nkimport/all/',follow=True)
expected = reverse('workouts_view')
self.assertRedirects(response,
expected_url=expected,
status_code=302,target_status_code=200)
self.assertEqual(response.status_code, 200)
@patch('rowers.nkstuff.requests.get', side_effect=mocked_requests)
@patch('rowers.nkstuff.requests.post', side_effect=mocked_requests)
@patch('rowers.nkimportutils.requests.session', side_effect=mocked_session)
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db) @patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
def test_nk_import(self, mock_get, mock_post, def test_nk_import(self, mock_get, mock_post,
mocked_session, mocked_session,
@@ -441,6 +476,34 @@ class NKObjects(DjangoTestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
w = Workout.objects.get(id=1)
#self.assertEqual(w.inboard,0.89)
#self.assertEqual(w.oarlength,2.87)
@patch('rowers.nkstuff.requests.get', side_effect=mocked_requests)
@patch('rowers.nkstuff.requests.post', side_effect=mocked_requests)
@patch('rowers.nkimportutils.requests.session', side_effect=mocked_session)
@patch('rowers.dataprep.getsmallrowdata_db', side_effect=mocked_getsmallrowdata_db)
def test_nk_import_impeller(self, mock_get, mock_post,
mocked_session,
mocked_getsmallrowdata_db):
result = rowers.nkstuff.rower_nk_token_refresh(self.u)
response = self.c.get('/rowers/workout/nkimport/404',follow=True)
self.assertRedirects(response,
expected_url='/rowers/workout/'+encoded1+'/edit/',
status_code=301,target_status_code=200)
self.assertEqual(response.status_code, 200)
response = self.c.get('/rowers/workout/'+encoded1+'/otwuseimpeller/', follow=True)
self.assertRedirects(response,
expected_url='/rowers/workout/'+encoded1+'/edit/',
status_code=302,target_status_code=200)
w = Workout.objects.get(id=1)
#self.assertTrue(w.impeller)
#@pytest.mark.django_db #@pytest.mark.django_db
+2
View File
@@ -15,6 +15,8 @@ import rowers.tasks as tasks
from rowers.views.racesviews import * from rowers.views.racesviews import *
from rowers.utils import calculate_age from rowers.utils import calculate_age
# to do - add test for manual form with image
@override_settings(TESTING=True) @override_settings(TESTING=True)
class ChallengesTest(TestCase): class ChallengesTest(TestCase):
def setUp(self): def setUp(self):
+36
View File
@@ -12,6 +12,42 @@ nu = datetime.datetime.now()
# interactive plots # interactive plots
from rowers import interactiveplots from rowers import interactiveplots
from rowers import dataprep from rowers import dataprep
from rowers.views.workoutviews import get_video_id
class OtherUnitTests(TestCase):
def test_get_video_id(self):
url1 = 'http://youtu.be/_lOT2p_FCvA'
url2 = 'www.youtube.com/watch?v=_lOT2p_FCvA&feature=feedu'
url3 = 'http://www.youtube.com/embed/_lOT2p_FCvA'
url4 = 'http://www.youtube.com/v/_lOT2p_FCvA?version=3&amp;hl=en_US'
url5 = 'https://www.youtube.com/watch?v=rTHlyTphWP0&index=6&list=PLjeDyYvG6-40qawYNR4juzvSOg-ezZ2a6'
url6 = 'youtube.com/watch?v=_lOT2p_FCvA'
expected = '_lOT2p_FCvA'
expected2 = 'rTHlyTphWP0'
result = get_video_id(url1)
self.assertEqual(result,expected)
result = get_video_id(url2)
self.assertEqual(result,expected)
result = get_video_id(url3)
self.assertEqual(result,expected)
result = get_video_id(url4)
self.assertEqual(result,expected)
result = get_video_id(url5)
self.assertEqual(result,expected2)
result = get_video_id(url6)
self.assertEqual(result,expected)
class DataPrepTests(TestCase): class DataPrepTests(TestCase):
def setUp(self): def setUp(self):
+13
View File
@@ -548,6 +548,19 @@ def do_sync(w,options, quick=False):
except KeyError: except KeyError:
pass pass
try:
if options['inboard'] != 0 and options['inboard'] != '':
w.inboard = options['inboard']
except KeyError:
pass
try:
if options['oarlength'] != 0 and options['oarlength'] != '':
w.oarlength = options['oarlength']
except KeyError:
pass
try: try:
if options['garminid'] != 0 and options['garminid'] != '': if options['garminid'] != 0 and options['garminid'] != '':
w.uploadedtogarmin = options['garminid'] w.uploadedtogarmin = options['garminid']
+1
View File
@@ -568,6 +568,7 @@ urlpatterns = [
re_path(r'^workout/c2import/all/$',views.workout_getc2workout_all,name='workout_getc2workout_all'), re_path(r'^workout/c2import/all/$',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/c2import/all/(?P<page>\d+)/$',views.workout_getc2workout_all,name='workout_getc2workout_all'),
re_path(r'^workout/nkimport/$',views.workout_nkimport_view,name='workout_nkimport_view'), re_path(r'^workout/nkimport/$',views.workout_nkimport_view,name='workout_nkimport_view'),
re_path(r'^workout/nkimport/(?P<startTime>\d+)/(?P<endTime>\d+)/$',views.workout_nkimport_view,name='workout_nkimport_view'),
re_path(r'^workout/nkimport/all/$',views.workout_getnkworkout_all,name='workout_getnkworkout_all'), re_path(r'^workout/nkimport/all/$',views.workout_getnkworkout_all,name='workout_getnkworkout_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'),
-123
View File
@@ -1108,126 +1108,3 @@ def strfdelta(tdelta):
) )
return res return res
def get_nk_intervalstats(workoutdata,strokedata):
intervals = workoutdata['intervals']
separator = "|"
stri = "Workout Details\n"
stri += "#-{sep}SDist{sep}-Split-{sep}-SPace-{sep}-Pwr-{sep}-SPM--{sep}-AvgHR-{sep}DPS-\n".format(
sep=separator)
i = 0
for interval in intervals:
id = interval['id']
sdist = interval['totalDistanceGps']
avgpace = interval['avgPaceGps']/1000.
avgpacetd = timedelta(seconds=avgpace)
newpacestring = strfdelta(avgpacetd)
elapsedSeconds = interval['elapsedTime']/1000. # secs
elapsedTime = datetime.datetime.utcfromtimestamp(elapsedSeconds)
newsplitstring = "%s.%i" % (elapsedTime.strftime("%M:%S"), elapsedTime.microsecond/100000)
pwr = interval['avgPower']
avghr = interval['avgHeartRate']
spm = interval['avgStrokeRate']
dps = interval['distStrokeGps']
stri += "{i:0>2}{sep}{sdist:0>5}{sep}{split}{sep}{space}{sep} {pwr:0>3} {sep}".format(
i=i + 1,
sdist=int(float(sdist)),
split=newsplitstring,
space=newpacestring,
pwr=int(pwr),
sep=separator,
)
stri += " {spm} {sep} {avghr:0>3} {sep}{dps:0>4.1f}\n".format(
sep=separator,
avghr=avghr,
spm=spm,
dps=dps,
)
i += 1
return stri
def get_nk_summary(workoutdata,strokedata):
name = workoutdata['name']
avgpace = workoutdata['avgPaceGps']/1000. # secs
avgpacetd = timedelta(seconds=avgpace)
avgpacestring = strfdelta(avgpacetd)
elapsedSeconds = workoutdata['elapsedTime']/1000. # secs
elapsedTime = datetime.datetime.utcfromtimestamp(elapsedSeconds)
timestring = "%s.%i" % (elapsedTime.strftime("%H:%M:%S"), elapsedTime.microsecond/100000)
dist = workoutdata['totalDistanceGps']
spm = workoutdata['avgStrokeRate']
avghr = workoutdata['avgHeartRate']
avgdps = workoutdata['distStrokeGps']
maxhr = strokedata['heartRate'].max()
pwr = workoutdata['avgPower']
sep = "|"
stri1 = "Workout Summary - " + name + "\n"
stri1 += "--{sep}Total{sep}--Total---{sep}--Avg--{sep}-Avg-{sep}-Avg--{sep}-Avg-{sep}-Max-{sep}-Avg\n".format(
sep=sep)
stri1 += "--{sep}Dist-{sep}--Time----{sep}-Pace--{sep}-Pwr-{sep}-SPM--{sep}-HR--{sep}-HR--{sep}-DPS\n".format(
sep=sep)
stri1 += "--{sep}{dist:0>5.0f}{sep}".format(
sep=sep,
dist=dist,
)
stri1 += timestring + sep + avgpacestring
stri1 += "{sep}{avgpower:0>5.1f}".format(
sep=sep,
avgpower=pwr,
)
stri1 += "{sep} {avgsr:2.1f} {sep}{avghr:0>5.1f}{sep}".format(
avgsr=spm,
sep=sep,
avghr=avghr
)
stri1 += "{maxhr:0>5.1f}{sep}{avgdps:0>4.1f}\n".format(
sep=sep,
maxhr=maxhr,
avgdps=avgdps
)
return stri1
return stri1
def get_nk_allstats(data,workoutdata):
stri = get_nk_summary(data, workoutdata) + \
get_nk_intervalstats(data, workoutdata)
return stri
#def get_workout(user,nkid):
def getdict(x, seatIndex=1):
seatStrokes = pd.DataFrame(x)
try:
seatStrokes = seatStrokes.set_index('seatIndex')
return dict(seatStrokes.loc[seatIndex])
except KeyError:
pass
return {}
+5 -2
View File
@@ -836,14 +836,14 @@ def workout_getnkworkout_all(request):
@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)
def workout_nkimport_view(request,userid=0): def workout_nkimport_view(request,userid=0,startTime=0,endTime=0):
r = getrequestrower(request,userid=userid) r = getrequestrower(request,userid=userid)
try: try:
thetoken = nk_open(request.user) thetoken = nk_open(request.user)
except NoTokenError: except NoTokenError:
return HttpResponseRedirect("/rowers/me/nkauthorize/") return HttpResponseRedirect("/rowers/me/nkauthorize/")
res = nkstuff.get_nk_workout_list(request.user) res = nkstuff.get_nk_workout_list(request.user,startTime=startTime,endTime=endTime)
if (res.status_code != 200): if (res.status_code != 200):
if (res.status_code == 401): if (res.status_code == 401):
@@ -882,6 +882,9 @@ def workout_nkimport_view(request,userid=0):
'start_date':arrow.get(item['startTime']), 'start_date':arrow.get(item['startTime']),
} for item in res.json()] } for item in res.json()]
#for item in res.json():
# print(item['startTime'],arrow.get(item['startTime']),item['name'])
workouts = [] workouts = []
for item in res.json(): for item in res.json():
-1
View File
@@ -636,7 +636,6 @@ def upgrade_checkouts_view(request):
@login_required() @login_required()
def downgrade_checkouts_view(request): def downgrade_checkouts_view(request):
print('aap')
if not PAYMENT_PROCESSING_ON: if not PAYMENT_PROCESSING_ON:
url = reverse('promembership') url = reverse('promembership')
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
+2
View File
@@ -336,6 +336,8 @@ def rower_exportsettings_view(request,userid=0):
'strava_auto_import':'stravatoken', 'strava_auto_import':'stravatoken',
'strava_auto_delete':'stravatoken', 'strava_auto_delete':'stravatoken',
'trainingpeaks_auto_export':'tptoken', 'trainingpeaks_auto_export':'tptoken',
'rp3_auto_import':'rp3token',
'nk_auto_import':'nktoken'
} }
r = getrequestrowercoachee(request,userid=userid) r = getrequestrowercoachee(request,userid=userid)
if request.method == 'POST': if request.method == 'POST':
+54 -64
View File
@@ -17,7 +17,7 @@ import rowers.utils as utils
from urllib.parse import urlparse, parse_qs from urllib.parse import urlparse, parse_qs
from json.decoder import JSONDecodeError from json.decoder import JSONDecodeError
def default(o): def default(o): # pragma: no cover
if isinstance(o, numpy.int64): return int(o) if isinstance(o, numpy.int64): return int(o)
if isinstance(o, numpy.int32): return int(o) if isinstance(o, numpy.int32): return int(o)
raise TypeError raise TypeError
@@ -52,7 +52,7 @@ def get_video_id(url):
return query.path.split('/')[2] return query.path.split('/')[2]
elif 'youtu.be' in query.hostname: elif 'youtu.be' in query.hostname:
return query.path[1:] return query.path[1:]
else: else: # pragma: no cover
raise ValueError raise ValueError
# Show a video compared with data # Show a video compared with data
@@ -60,7 +60,7 @@ def workout_video_view_mini(request,id=''):
try: try:
id = encoder.decode_hex(id) id = encoder.decode_hex(id)
analysis = VideoAnalysis.objects.get(id=id) analysis = VideoAnalysis.objects.get(id=id)
except VideoAnalysis.DoesNotExist: except VideoAnalysis.DoesNotExist: # pragma: no cover
raise Http404("Video Analysis does not exist") raise Http404("Video Analysis does not exist")
w = analysis.workout w = analysis.workout
@@ -173,7 +173,7 @@ def workout_video_view(request,id=''):
try: try:
id = encoder.decode_hex(id) id = encoder.decode_hex(id)
analysis = VideoAnalysis.objects.get(id=id) analysis = VideoAnalysis.objects.get(id=id)
except VideoAnalysis.DoesNotExist: except VideoAnalysis.DoesNotExist: # pragma: no cover
raise Http404("Video Analysis does not exist") raise Http404("Video Analysis does not exist")
w = analysis.workout w = analysis.workout
@@ -199,7 +199,7 @@ def workout_video_view(request,id=''):
video_id = form.cleaned_data['url'] video_id = form.cleaned_data['url']
try: try:
video_id = get_video_id(form.cleaned_data['url']) video_id = get_video_id(form.cleaned_data['url'])
except (TypeError,ValueError): except (TypeError,ValueError): # pragma: no cover
pass pass
delay = form.cleaned_data['delay'] delay = form.cleaned_data['delay']
metricsgroups = metricsform.cleaned_data['groups'] metricsgroups = metricsform.cleaned_data['groups']
@@ -314,7 +314,7 @@ def workout_video_create_view(request,id=0):
url = reverse('workout_video_view', url = reverse('workout_video_view',
kwargs={'id':encoder.encode_hex(analysis.id)}) kwargs={'id':encoder.encode_hex(analysis.id)})
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
except IntegrityError: except IntegrityError: # pragma: no cover
messages.error(request,'You cannot save two video analysis with the same YouTube video and Workout. Redirecting to your existing analysis') messages.error(request,'You cannot save two video analysis with the same YouTube video and Workout. Redirecting to your existing analysis')
analysis = VideoAnalysis.objects.filter(workout=w,video_id=video_id) analysis = VideoAnalysis.objects.filter(workout=w,video_id=video_id)
if analysis: if analysis:
@@ -577,7 +577,7 @@ def addmanual_view(request,raceid=0):
if form.is_valid() and metricsform.is_valid(): if form.is_valid() and metricsform.is_valid():
# Get values from form # Get values from form
name = form.cleaned_data['name'] name = form.cleaned_data['name']
if name == '': if name == '': # pragma: no cover
name = 'Manual Entry' name = 'Manual Entry'
date = form.cleaned_data['date'] date = form.cleaned_data['date']
starttime = form.cleaned_data['starttime'] starttime = form.cleaned_data['starttime']
@@ -590,7 +590,7 @@ def addmanual_view(request,raceid=0):
rpe = form.cleaned_data['rpe'] rpe = form.cleaned_data['rpe']
if not rpe: if not rpe:
rpe = -1 rpe = -1
except KeyError: except KeyError: # pragma: no cover
rpe = -1 rpe = -1
notes = form.cleaned_data['notes'] notes = form.cleaned_data['notes']
thetimezone = form.cleaned_data['timezone'] thetimezone = form.cleaned_data['timezone']
@@ -601,25 +601,25 @@ def addmanual_view(request,raceid=0):
try: try:
ps = form.cleaned_data['plannedsession'] ps = form.cleaned_data['plannedsession']
except KeyError: except KeyError: # pragma: no cover
ps = None ps = None
try: try:
boattype = request.POST['boattype'] boattype = request.POST['boattype']
except KeyError: except KeyError: # pragma: no cover
boattype = '1x' boattype = '1x'
try: try:
privacy = request.POST['privacy'] privacy = request.POST['privacy']
except KeyError: except KeyError: # pragma: no cover
privacy = 'visible' privacy = 'visible'
try: try:
rankingpiece = form.cleaned_data['rankingpiece'] rankingpiece = form.cleaned_data['rankingpiece']
except KeyError: except KeyError: # pragma: no cover
rankingpiece = False rankingpiece = False
try: try:
duplicate = form.cleaned_data['duplicate'] duplicate = form.cleaned_data['duplicate']
except KeyError: except KeyError: # pragma: no cover
duplicate = False duplicate = False
if private: if private:
@@ -654,7 +654,7 @@ def addmanual_view(request,raceid=0):
if message: if message: # pragma: no cover
messages.error(request,message) messages.error(request,message)
if id: if id:
@@ -871,7 +871,7 @@ def workouts_join_view(request,userid=0):
setprivate=set_private, setprivate=set_private,
killparents=killparents) killparents=killparents)
if message: if message: # pragma: no cover
messages.error(request,message) messages.error(request,message)
url = reverse(r.defaultlandingpage, url = reverse(r.defaultlandingpage,
@@ -920,13 +920,13 @@ def video_selectworkout(request,userid=0,teamid=0):
options['userid'] = userid options['userid'] = userid
try: try:
workouttypes = options['workouttypes'] workouttypes = options['workouttypes']
except KeyError: except KeyError: # pragma: no cover
workouttypes = ['rower','dynamic','slides'] workouttypes = ['rower','dynamic','slides']
try: try:
modalities = options['modalities'] modalities = options['modalities']
modality = modalities[0] modality = modalities[0]
except KeyError: except KeyError: # pragma: no cover
modalities = [m[0] for m in mytypes.workouttypes_ordered.items()] modalities = [m[0] for m in mytypes.workouttypes_ordered.items()]
modality = 'all' modality = 'all'
@@ -934,11 +934,11 @@ def video_selectworkout(request,userid=0,teamid=0):
try: try:
rankingonly = options['rankingonly'] rankingonly = options['rankingonly']
except KeyError: except KeyError: # pragma: no cover
rankingonly = False rankingonly = False
query = request.GET.get('q') query = request.GET.get('q')
if query: if query: # pragma: no cover
query_list = query.split() query_list = query.split()
workouts = workouts.filter( workouts = workouts.filter(
reduce(operator.and_, reduce(operator.and_,
@@ -1005,7 +1005,7 @@ def video_selectworkout(request,userid=0,teamid=0):
startdate = datetime.datetime.combine(startdate,datetime.time()) startdate = datetime.datetime.combine(startdate,datetime.time())
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
if enddate < startdate: if enddate < startdate: # pragma: no cover
s = enddate s = enddate
enddate = startdate enddate = startdate
startdate = s startdate = s
@@ -1168,7 +1168,7 @@ def workouts_join_select(request,
if enddatestring: if enddatestring:
enddate = iso8601.parse_date(enddatestring) enddate = iso8601.parse_date(enddatestring)
if enddate < startdate: if enddate < startdate: # pragma: no cover
s = enddate s = enddate
enddate = startdate enddate = startdate
startdate = s startdate = s
@@ -1279,7 +1279,7 @@ def remove_power_view(request,id=0):
try: try:
os.remove('media/cpdata_{id}.parquet.gz'.format(id=workout.id)) os.remove('media/cpdata_{id}.parquet.gz'.format(id=workout.id))
except OSError: except OSError: # pragma: no cover
pass pass
f = workout.csvfilename f = workout.csvfilename
@@ -1412,7 +1412,7 @@ def team_comparison_select(request,
if enddatestring: if enddatestring:
enddate = iso8601.parse_date(enddatestring) enddate = iso8601.parse_date(enddatestring)
if enddate < startdate: if enddate < startdate: # pragma: no cover
s = enddate s = enddate
enddate = startdate enddate = startdate
startdate = s startdate = s
@@ -1445,7 +1445,7 @@ def team_comparison_select(request,
workouts = workouts.exclude(rankingpiece=False) workouts = workouts.exclude(rankingpiece=False)
query = request.GET.get('q') query = request.GET.get('q')
if query: if query: # pragma: no cover
query_list = query.split() query_list = query.split()
workouts = workouts.filter( workouts = workouts.filter(
reduce(operator.and_, reduce(operator.and_,
@@ -2034,7 +2034,7 @@ def workouts_view(request,message='',successmessage='',
#enddate = enddate+datetime.timedelta(days=1) #enddate = enddate+datetime.timedelta(days=1)
if enddate < startdate: if enddate < startdate: # pragma: no cover
s = enddate s = enddate
enddate = startdate enddate = startdate
startdate = s startdate = s
@@ -4859,8 +4859,6 @@ def workout_upload_api(request):
message = {'status':'false','message':'this view cannot be accessed through GET'} message = {'status':'false','message':'this view cannot be accessed through GET'}
return JSONResponse(status=403,data=message) return JSONResponse(status=403,data=message)
# test if JSON # test if JSON
try: try:
json_data = json.loads(request.body) json_data = json.loads(request.body)
@@ -4907,38 +4905,24 @@ def workout_upload_api(request):
message = {'status':'false','message':'could not find file'} message = {'status':'false','message':'could not find file'}
return JSONResponse(status=400,data=message) return JSONResponse(status=400,data=message)
try: # sync related IDs
stravaid = post_data['stravaid'] stravaid = post_data.get('stravaid','')
except KeyError: c2id = post_data.get('c2id','')
stravaid = '' nkid = post_data.get('nkid','')
rp3id = post_data.get('nkid','')
garminid = post_data.get('garminid',0)
try: startdatetime = post_data.get('startdatetime','')
c2id = post_data['c2id'] oarlockfirmware = post_data.get('oarlockfirmware',None)
except KeyError: inboard = post_data.get('inboard',None)
c2id = '' oarlength = post_data.get('oarlength',None)
useImpeller = post_data.get('useImpeller',False)
try: totalDistance = post_data.get('totalDistance',None)
nkid = post_data['nkid'] elapsedTime = post_data.get('elapsedTime',None)
except KeyError: summary = post_data.get('summary',None)
nkid = ''
try:
rp3id = post_data['rp3id']
except KeyError:
rp3id = ''
try:
garminid = post_data['garminid']
except KeyError:
garminid = 0
try:
startdatetime = post_data['startdatetime']
except KeyError:
startdatetime = ''
r = None r = None
if form.is_valid(): if form.is_valid():
t = form.cleaned_data['title'] t = form.cleaned_data['title']
@@ -5011,6 +4995,10 @@ def workout_upload_api(request):
notes=notes, notes=notes,
uploadoptions=post_data, uploadoptions=post_data,
startdatetime=startdatetime, startdatetime=startdatetime,
oarlockfirmware=oarlockfirmware,
inboard=inboard,
oarlength=oarlength,
impeller=useImpeller,
) )
if id == 0: if id == 0:
@@ -5033,21 +5021,23 @@ def workout_upload_api(request):
plottype = r.staticchartonupload plottype = r.staticchartonupload
res, jobid = uploads.make_plot(r,w,f1,f2,plottype,t) res, jobid = uploads.make_plot(r,w,f1,f2,plottype,t)
try: if inboard:
oarlength = post_data['oarlength']
inboard = post_data['inboard']
w.inboard = inboard w.inboard = inboard
w.save()
if oarlength:
w.oarlength = oarlength w.oarlength = oarlength
w.save() w.save()
except KeyError:
pass
try: if totalDistance:
summary = post_data['summary'] w.distance = totalDistance
w.save()
if elapsedTime:
w.duration = totaltime_sec_to_string(elapsedTime)
if summary:
w.summary = summary w.summary = summary
w.save() w.save()
except KeyError:
pass
uploads.do_sync(w,post_data,quick=True) uploads.do_sync(w,post_data,quick=True)