Merge branch 'feature/mergeworkoutcreation' into develop
This commit is contained in:
@@ -447,7 +447,6 @@ def get_username(access_token):
|
||||
|
||||
me_json = response.json()
|
||||
|
||||
|
||||
return me_json['data']['username']
|
||||
|
||||
# Get user id, having access token
|
||||
@@ -463,9 +462,12 @@ def get_userid(access_token):
|
||||
|
||||
|
||||
me_json = response.json()
|
||||
try:
|
||||
res = me_json['data']['id']
|
||||
except KeyError:
|
||||
res = 0
|
||||
|
||||
|
||||
return me_json['data']['id']
|
||||
return res
|
||||
|
||||
# For debugging purposes
|
||||
def process_callback(request):
|
||||
@@ -515,16 +517,19 @@ def workout_c2_upload(user,w):
|
||||
def rower_c2_token_refresh(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
res = do_refresh_token(r.c2refreshtoken)
|
||||
access_token = res[0]
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
expirydatetime = timezone.now()+timedelta(seconds=expires_in)
|
||||
if res[0]:
|
||||
access_token = res[0]
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
expirydatetime = timezone.now()+timedelta(seconds=expires_in)
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
r.c2token = access_token
|
||||
r.tokenexpirydate = expirydatetime
|
||||
r.c2refreshtoken = refresh_token
|
||||
r = Rower.objects.get(user=user)
|
||||
r.c2token = access_token
|
||||
r.tokenexpirydate = expirydatetime
|
||||
r.c2refreshtoken = refresh_token
|
||||
|
||||
r.save()
|
||||
return r.c2token
|
||||
r.save()
|
||||
return r.c2token
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ from celery import Celery
|
||||
# on Windows, so I use Celery on my notebook.
|
||||
|
||||
# set the default Django settings module for the 'celery' program.
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rowsandall_app.settings')
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'rowsandall_app.settings_dev')
|
||||
|
||||
from django.conf import settings # noqa
|
||||
|
||||
@@ -25,6 +25,8 @@ app.config_from_object('django.conf:settings')
|
||||
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
|
||||
|
||||
|
||||
database_url = 'sqlite:///db.sqlite3'
|
||||
|
||||
@app.task(bind=True)
|
||||
def debug_task(self):
|
||||
print('Request: {0!r}'.format(self.request))
|
||||
|
||||
@@ -15,11 +15,25 @@ from pytz import timezone as tz,utc
|
||||
|
||||
from django.utils.timezone import get_current_timezone
|
||||
thetimezone = get_current_timezone()
|
||||
from rowingdata import (
|
||||
TCXParser,RowProParser,ErgDataParser,TCXParserNoHR,
|
||||
BoatCoachParser,RowPerfectParser,BoatCoachAdvancedParser,
|
||||
MysteryParser,
|
||||
painsledDesktopParser,speedcoachParser,ErgStickParser,
|
||||
SpeedCoach2Parser,FITParser,fitsummarydata,
|
||||
make_cumvalues,
|
||||
summarydata,get_file_type,
|
||||
)
|
||||
|
||||
from rowers.models import Team
|
||||
|
||||
import os
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import itertools
|
||||
|
||||
from tasks import handle_sendemail_unrecognized
|
||||
|
||||
from django.conf import settings
|
||||
from sqlalchemy import create_engine
|
||||
import sqlalchemy as sa
|
||||
@@ -205,115 +219,55 @@ def timedeltaconv(x):
|
||||
|
||||
return dt
|
||||
|
||||
# Create new workout from file and store it in the database
|
||||
# This routine should be used everywhere in views.py and mailprocessing.py
|
||||
# Currently there is code duplication
|
||||
def new_workout_from_file(r,f2,
|
||||
workouttype='rower',
|
||||
title='Workout',
|
||||
notes=''):
|
||||
|
||||
fileformat = get_file_type(f2)
|
||||
summary = ''
|
||||
# handle non-Painsled
|
||||
if (fileformat != 'csv'):
|
||||
# handle RowPro:
|
||||
if (fileformat == 'rp'):
|
||||
row = RowProParser(f2)
|
||||
# handle TCX
|
||||
if (fileformat == 'tcx'):
|
||||
row = TCXParser(f2)
|
||||
|
||||
# handle Mystery
|
||||
if (fileformat == 'mystery'):
|
||||
row = MysteryParser(f2)
|
||||
|
||||
# handle TCX no HR
|
||||
if (fileformat == 'tcxnohr'):
|
||||
row = TCXParserNoHR(f2)
|
||||
|
||||
# handle ErgData
|
||||
if (fileformat == 'ergdata'):
|
||||
row = ErgDataParser(f2)
|
||||
|
||||
# handle BoatCoach
|
||||
if (fileformat == 'boatcoach'):
|
||||
row = BoatCoachParser(f2)
|
||||
|
||||
# handle painsled desktop
|
||||
if (fileformat == 'painsleddesktop'):
|
||||
row = painsledDesktopParser(f2)
|
||||
|
||||
# handle speed coach GPS
|
||||
if (fileformat == 'speedcoach'):
|
||||
row = speedcoachParser(f2)
|
||||
|
||||
# handle speed coach GPS 2
|
||||
if (fileformat == 'speedcoach2'):
|
||||
row = SpeedCoach2Parser(f2)
|
||||
summary = row.allstats()
|
||||
|
||||
|
||||
# handle ErgStick
|
||||
if (fileformat == 'ergstick'):
|
||||
row = ErgStickParser(f2)
|
||||
|
||||
# handle FIT
|
||||
if (fileformat == 'fit'):
|
||||
row = FITParser(f2)
|
||||
s = fitsummarydata(f2)
|
||||
s.setsummary()
|
||||
summary = s.summarytext
|
||||
|
||||
|
||||
f_to_be_deleted = f2
|
||||
# should delete file
|
||||
f2 = f2[:-4]+'o.csv'
|
||||
row.write_csv(f2,gzip=True)
|
||||
|
||||
#os.remove(f2)
|
||||
try:
|
||||
os.remove(f_to_be_deleted)
|
||||
except:
|
||||
os.remove(f_to_be_deleted+'.gz')
|
||||
# Processes painsled CSV file to database
|
||||
def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
dosummary=True,title='Workout',
|
||||
notes='',totaldist=0,totaltime=0):
|
||||
message = None
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
r.pw_tr,r.pw_an])/r.ftp
|
||||
|
||||
# make workout and put in database
|
||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||
hrut1=r.ut1,hrat=r.at,
|
||||
hrtr=r.tr,hran=r.an,ftp=r.ftp)
|
||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
||||
powerperc=powerperc,powerzones=r.powerzones)
|
||||
row = rdata(f2,rower=rr)
|
||||
if row == 0:
|
||||
return HttpResponse("Error: CSV Data File Not Found")
|
||||
return (0,'Error: CSV data file not found')
|
||||
|
||||
# auto smoothing
|
||||
pace = row.df[' Stroke500mPace (sec/500m)'].values
|
||||
velo = 500./pace
|
||||
if dosmooth:
|
||||
# auto smoothing
|
||||
pace = row.df[' Stroke500mPace (sec/500m)'].values
|
||||
velo = 500./pace
|
||||
|
||||
f = row.df['TimeStamp (sec)'].diff().mean()
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
if not 'originalvelo' in row.df:
|
||||
row.df['originalvelo'] = velo
|
||||
f = row.df['TimeStamp (sec)'].diff().mean()
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
if not 'originalvelo' in row.df:
|
||||
row.df['originalvelo'] = velo
|
||||
|
||||
if windowsize > 3 and windowsize<len(velo):
|
||||
velo2 = savgol_filter(velo,windowsize,3)
|
||||
else:
|
||||
velo2 = velo
|
||||
if windowsize > 3 and windowsize<len(velo):
|
||||
velo2 = savgol_filter(velo,windowsize,3)
|
||||
else:
|
||||
velo2 = velo
|
||||
|
||||
velo3 = pd.Series(velo2)
|
||||
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
||||
velo3 = velo3.fillna(method='ffill')
|
||||
velo3 = pd.Series(velo2)
|
||||
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
||||
velo3 = velo3.fillna(method='ffill')
|
||||
|
||||
pace2 = 500./abs(velo3)
|
||||
pace2 = 500./abs(velo3)
|
||||
|
||||
row.df[' Stroke500mPace (sec/500m)'] = pace2
|
||||
row.df[' Stroke500mPace (sec/500m)'] = pace2
|
||||
|
||||
row.df = row.df.fillna(0)
|
||||
row.df = row.df.fillna(0)
|
||||
|
||||
row.write_csv(f2,gzip=True)
|
||||
try:
|
||||
os.remove(f2)
|
||||
except:
|
||||
pass
|
||||
row.write_csv(f2,gzip=True)
|
||||
try:
|
||||
os.remove(f2)
|
||||
except:
|
||||
pass
|
||||
|
||||
# recalculate power data
|
||||
if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides':
|
||||
@@ -323,24 +277,32 @@ def new_workout_from_file(r,f2,
|
||||
except:
|
||||
pass
|
||||
|
||||
if fileformat != 'fit' and summary == '':
|
||||
summary = row.summary()
|
||||
summary += '\n'
|
||||
summary += row.intervalstats_painsled()
|
||||
|
||||
averagehr = row.df[' HRCur (bpm)'].mean()
|
||||
maxhr = row.df[' HRCur (bpm)'].max()
|
||||
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
|
||||
if totaldist == 0:
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
if totaltime == 0:
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
|
||||
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
if hours>23:
|
||||
message = 'Warning: The workout duration was longer than 23 hours'
|
||||
hours = 23
|
||||
|
||||
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)
|
||||
|
||||
if dosummary:
|
||||
summary = row.summary()
|
||||
summary += '\n'
|
||||
summary += row.intervalstats()
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutstartdatetime = thetimezone.localize(row.rowdatetime).astimezone(utc)
|
||||
@@ -360,11 +322,152 @@ def new_workout_from_file(r,f2,
|
||||
maxhr=maxhr,averagehr=averagehr,
|
||||
startdatetime=workoutstartdatetime)
|
||||
|
||||
w.save()
|
||||
# put stroke data in database
|
||||
res = dataprep(row.df,id=w.id,bands=True,barchart=True,otwpower=True,empower=True)
|
||||
|
||||
return True
|
||||
w.save()
|
||||
|
||||
ts = Team.objects.filter(rower=r)
|
||||
|
||||
for t in ts:
|
||||
w.team.add(t)
|
||||
|
||||
# put stroke data in database
|
||||
res = dataprep(row.df,id=w.id,bands=True,
|
||||
barchart=True,otwpower=True,empower=True)
|
||||
|
||||
return (w.id,message)
|
||||
|
||||
def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
# handle RowPro:
|
||||
if (fileformat == 'rp'):
|
||||
row = RowProParser(f2)
|
||||
# handle TCX
|
||||
if (fileformat == 'tcx'):
|
||||
row = TCXParser(f2)
|
||||
|
||||
# handle Mystery
|
||||
if (fileformat == 'mystery'):
|
||||
row = MysteryParser(f2)
|
||||
|
||||
# handle TCX no HR
|
||||
if (fileformat == 'tcxnohr'):
|
||||
row = TCXParserNoHR(f2)
|
||||
|
||||
# handle RowPerfect
|
||||
if (fileformat == 'rowperfect3'):
|
||||
row = RowPerfectParser(f2)
|
||||
|
||||
# handle ErgData
|
||||
if (fileformat == 'ergdata'):
|
||||
row = ErgDataParser(f2)
|
||||
|
||||
# handle Mike
|
||||
if (fileformat == 'bcmike'):
|
||||
row = BoatCoachAdvancedParser(f2)
|
||||
|
||||
# handle BoatCoach
|
||||
if (fileformat == 'boatcoach'):
|
||||
row = BoatCoachParser(f2)
|
||||
|
||||
# handle painsled desktop
|
||||
if (fileformat == 'painsleddesktop'):
|
||||
row = painsledDesktopParser(f2)
|
||||
|
||||
# handle speed coach GPS
|
||||
if (fileformat == 'speedcoach'):
|
||||
row = speedcoachParser(f2)
|
||||
|
||||
# handle speed coach GPS 2
|
||||
if (fileformat == 'speedcoach2'):
|
||||
row = SpeedCoach2Parser(f2)
|
||||
try:
|
||||
summary = row.allstats()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# handle ErgStick
|
||||
if (fileformat == 'ergstick'):
|
||||
row = ErgStickParser(f2)
|
||||
|
||||
# handle FIT
|
||||
if (fileformat == 'fit'):
|
||||
row = FITParser(f2)
|
||||
s = fitsummarydata(f2)
|
||||
s.setsummary()
|
||||
summary = s.summarytext
|
||||
|
||||
|
||||
f_to_be_deleted = f2
|
||||
# should delete file
|
||||
f2 = f2[:-4]+'o.csv'
|
||||
row.write_csv(f2,gzip=True)
|
||||
|
||||
#os.remove(f2)
|
||||
try:
|
||||
os.remove(f_to_be_deleted)
|
||||
except:
|
||||
os.remove(f_to_be_deleted+'.gz')
|
||||
|
||||
return (f2,summary)
|
||||
|
||||
# Create new workout from file and store it in the database
|
||||
# This routine should be used everywhere in views.py and mailprocessing.py
|
||||
# Currently there is code duplication
|
||||
def new_workout_from_file(r,f2,
|
||||
workouttype='rower',
|
||||
title='Workout',
|
||||
notes=''):
|
||||
message = None
|
||||
fileformat = get_file_type(f2)
|
||||
summary = ''
|
||||
if len(fileformat)==3 and fileformat[0]=='zip':
|
||||
f_to_be_deleted = f2
|
||||
with zipfile.ZipFile(f2) as z:
|
||||
# for now, we're getting only the first file
|
||||
# from the NK zip file (issue #69 on bitbucket)
|
||||
f2 = z.extract(z.namelist()[0],path='media/')
|
||||
fileformat = fileformat[2]
|
||||
os.remove(f_to_be_deleted)
|
||||
|
||||
# Some people try to upload Concept2 logbook summaries
|
||||
if fileformat == 'c2log':
|
||||
os.remove(f2)
|
||||
message = "This C2 logbook summary does not contain stroke data. Please download the Export Stroke Data file from the workout details on the C2 logbook."
|
||||
return (0,message)
|
||||
|
||||
# Some people try to upload RowPro summary logs
|
||||
if fileformat == 'rowprolog':
|
||||
os.remove(f2)
|
||||
message = "This RowPro logbook summary does not contain stroke data. Please use the Stroke Data CSV file for the individual workout in your log."
|
||||
return (0,message)
|
||||
|
||||
# Sometimes people try an unsupported file type.
|
||||
# Send an email to info@rowsandall.com with the file attached
|
||||
# for me to check if it is a bug, or a new file type
|
||||
# worth supporting
|
||||
if fileformat == 'unknown':
|
||||
message = "We couldn't recognize the file type"
|
||||
if settings.DEBUG:
|
||||
res = handle_sendemail_unrecognized.delay(f2,
|
||||
request.user.email)
|
||||
|
||||
else:
|
||||
res = queuehigh.enqueue(handle_sendemail_unrecognized,
|
||||
f2,request.user.email)
|
||||
return (0,'message')
|
||||
|
||||
# handle non-Painsled by converting it to painsled compatible CSV
|
||||
if (fileformat != 'csv'):
|
||||
f2,summary = handle_nonpainsled(f2,fileformat,summary=summary)
|
||||
|
||||
|
||||
dosummary = (fileformat != 'fit')
|
||||
id,message = save_workout_database(f2,r,
|
||||
workouttype=workouttype,
|
||||
dosummary=dosummary,
|
||||
title=title)
|
||||
|
||||
return (id,message)
|
||||
|
||||
# Compare the data from the CSV file and the database
|
||||
# Currently only calculates number of strokes. To be expanded with
|
||||
|
||||
@@ -32,10 +32,14 @@ class CNsummaryForm(forms.Form):
|
||||
class SummaryStringForm(forms.Form):
|
||||
intervalstring = forms.CharField(max_length=255,label='Workout Description')
|
||||
|
||||
# little window to type a Team invitation code
|
||||
class TeamInviteCodeForm(forms.Form):
|
||||
code = forms.CharField(max_length=10,label='Team Code',
|
||||
)
|
||||
|
||||
# Used for testing the POST API for StrokeData
|
||||
class StrokeDataForm(forms.Form):
|
||||
strokedata = forms.CharField(label='payload',
|
||||
widget=forms.Textarea)
|
||||
strokedata = forms.CharField(label='payload',widget=forms.Textarea)
|
||||
|
||||
# The form used for uploading files
|
||||
class DocumentsForm(forms.Form):
|
||||
|
||||
@@ -159,15 +159,19 @@ def processattachments_debug():
|
||||
# Need to move the code to a subroutine used both in views.py and here
|
||||
def make_new_workout_from_email(rr,f2,name,cntr=0):
|
||||
workouttype = 'rower'
|
||||
f2 = f2.name
|
||||
fileformat = get_file_type('media/'+f2)
|
||||
|
||||
try:
|
||||
f2 = f2.name
|
||||
fileformat = get_file_type('media/'+f2)
|
||||
except IOError:
|
||||
f2 = f2.name+'.gz'
|
||||
fileformat = get_file_type('media/'+f2)
|
||||
|
||||
if len(fileformat)==3 and fileformat[0]=='zip':
|
||||
f_to_be_deleted = f2
|
||||
with zipfile.ZipFile('media/'+f2) as z:
|
||||
f2 = z.extract(z.namelist()[0],path='media/')[6:]
|
||||
fileformat = fileformat[2]
|
||||
print f2
|
||||
|
||||
if fileformat == 'unknown':
|
||||
if settings.DEBUG:
|
||||
@@ -182,149 +186,42 @@ def make_new_workout_from_email(rr,f2,name,cntr=0):
|
||||
|
||||
summary = ''
|
||||
# handle non-Painsled
|
||||
if (fileformat != 'csv'):
|
||||
# handle RowPro:
|
||||
if (fileformat == 'rp'):
|
||||
row = RowProParser('media/'+f2)
|
||||
if fileformat != 'csv':
|
||||
f3,summary = dataprep.handle_nonpainsled('media/'+f2,fileformat,summary)
|
||||
else:
|
||||
f3 = 'media/'+f2
|
||||
|
||||
# handle TCX
|
||||
if (fileformat == 'tcx'):
|
||||
row = TCXParser('media/'+f2)
|
||||
|
||||
# handle Mystery
|
||||
if (fileformat == 'mystery'):
|
||||
row = MysteryParser('media/'+f2)
|
||||
|
||||
# handle TCX no HR
|
||||
if (fileformat == 'tcxnohr'):
|
||||
row = TCXParserNoHR('media/'+f2)
|
||||
|
||||
# handle ErgData
|
||||
if (fileformat == 'ergdata'):
|
||||
row = ErgDataParser('media/'+f2)
|
||||
|
||||
# handle BoatCoach
|
||||
if (fileformat == 'boatcoach'):
|
||||
row = BoatCoachParser('media/'+f2)
|
||||
|
||||
# handle painsled desktop
|
||||
if (fileformat == 'painsleddesktop'):
|
||||
row = painsledDesktopParser('media/'+f2)
|
||||
|
||||
# handle speed coach GPS
|
||||
if (fileformat == 'speedcoach'):
|
||||
row = speedcoachParser('media/'+f2)
|
||||
|
||||
# handle speed coach GPS 2
|
||||
if (fileformat == 'speedcoach2'):
|
||||
row = SpeedCoach2Parser('media/'+f2)
|
||||
|
||||
# handle ErgStick
|
||||
if (fileformat == 'ergstick'):
|
||||
row = ErgStickParser('media/'+f2)
|
||||
|
||||
# handle FIT
|
||||
if (fileformat == 'fit'):
|
||||
row = FITParser('media/'+f2)
|
||||
s = fitsummarydata('media/'+f2)
|
||||
s.setsummary()
|
||||
summary = s.summarytext
|
||||
|
||||
timestr = time.strftime("%Y%m%d-%H%M%S")
|
||||
filename = timestr+str(cntr)+'o.csv'
|
||||
row.write_csv('media/'+filename,gzip=True)
|
||||
f2 = filename
|
||||
|
||||
# make workout and put in database
|
||||
#r = rrower(hrmax=rr.max,hrut2=rr.ut2,
|
||||
# hrut1=rr.ut1,hrat=rr.at,
|
||||
# hrtr=rr.tr,hran=rr.an,ftp=r.ftp)
|
||||
row = rdata('media/'+f2) #,rower=r)
|
||||
row = rdata(f3) #,rower=r)
|
||||
if row == 0:
|
||||
return 0
|
||||
|
||||
|
||||
# change filename
|
||||
if f2[:5] != 'media':
|
||||
timestr = time.strftime("%Y%m%d-%H%M%S")
|
||||
f2 = 'media/'+timestr+str(cntr)+'o.csv'
|
||||
|
||||
# auto smoothing
|
||||
pace = row.df[' Stroke500mPace (sec/500m)'].values
|
||||
velo = 500./pace
|
||||
|
||||
f = row.df['TimeStamp (sec)'].diff().mean()
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
|
||||
if not 'originalvelo' in row.df:
|
||||
row.df['originalvelo'] = velo
|
||||
|
||||
if windowsize > 3:
|
||||
velo2 = savgol_filter(velo,windowsize,3)
|
||||
else:
|
||||
velo2 = velo
|
||||
|
||||
pace2 = 500./abs(velo2)
|
||||
row.df[' Stroke500mPace (sec/500m)'] = pace2
|
||||
|
||||
row.df = row.df.fillna(0)
|
||||
|
||||
row.write_csv(f2,gzip=True)
|
||||
dosummary = (fileformat != 'fit')
|
||||
|
||||
# recalculate power data
|
||||
if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides':
|
||||
try:
|
||||
row.erg_recalculatepower()
|
||||
# row.spm_fromtimestamps()
|
||||
row.write_csv(f2,gzip=True)
|
||||
except:
|
||||
pass
|
||||
|
||||
if fileformat != 'fit':
|
||||
summary = row.summary()
|
||||
summary += '\n'
|
||||
summary += row.intervalstats_painsled()
|
||||
|
||||
averagehr = row.df[' HRCur (bpm)'].mean()
|
||||
maxhr = row.df[' HRCur (bpm)'].max()
|
||||
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
|
||||
|
||||
|
||||
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')
|
||||
|
||||
notes = 'imported through email'
|
||||
if name == '':
|
||||
name = 'imported through email'
|
||||
|
||||
w = Workout(user=rr,name=name,date=workoutdate,
|
||||
workouttype=workouttype,
|
||||
duration=duration,distance=totaldist,
|
||||
weightcategory=rr.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=f2,notes=notes,summary=summary,
|
||||
maxhr=maxhr,averagehr=averagehr,
|
||||
startdatetime=row.rowdatetime)
|
||||
|
||||
w.save()
|
||||
|
||||
# put stroke data in database
|
||||
res = dataprep.dataprep(row.df,id=w.id,
|
||||
bands=True,barchart=True,
|
||||
otwpower=True,empower=True)
|
||||
id,message = dataprep.save_workout_database(f2,rr,
|
||||
workouttype=workouttype,
|
||||
dosummary=dosummary,
|
||||
title=name,
|
||||
notes='imported through email')
|
||||
|
||||
|
||||
return w.id
|
||||
return id
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,10 +22,7 @@ from rowsandall_app.settings import BASE_DIR
|
||||
from rowingdata import rower as rrower
|
||||
from rowingdata import main as rmain
|
||||
from rowingdata import rowingdata as rrdata
|
||||
from rowingdata import TCXParser,RowProParser,ErgDataParser,TCXParserNoHR
|
||||
from rowingdata import MysteryParser
|
||||
from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser
|
||||
from rowingdata import SpeedCoach2Parser,FITParser,fitsummarydata
|
||||
|
||||
from rowingdata import make_cumvalues
|
||||
from rowingdata import summarydata,get_file_type
|
||||
|
||||
|
||||
@@ -377,9 +377,14 @@ class Workout(models.Model):
|
||||
date = self.date
|
||||
name = self.name
|
||||
|
||||
str = date.strftime('%Y-%m-%d')+'_'+name
|
||||
try:
|
||||
stri = date.strftime('%Y-%m-%d')+'_'+name
|
||||
except AttributeError:
|
||||
stri = str(date)+'_'+name
|
||||
|
||||
return str
|
||||
|
||||
|
||||
return stri
|
||||
|
||||
# delete files belonging to workout instance
|
||||
# related GraphImage objects should be deleted automatically
|
||||
|
||||
@@ -31,6 +31,8 @@ from rowers.tasks import (
|
||||
inviteduration = 14 # days
|
||||
|
||||
def update_team(t,name,manager,private,notes):
|
||||
if t.manager != manager:
|
||||
return (0,'You are not the manager of this team')
|
||||
try:
|
||||
t.name = name
|
||||
t.manager = manager
|
||||
|
||||
@@ -100,7 +100,25 @@
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Manual code redeem</h3>
|
||||
<div class="grid_4 alpha">
|
||||
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
|
||||
{% if form.errors %}
|
||||
<p style\"color: red;">
|
||||
Please correct the error{{ form.errors|pluralize }} below.
|
||||
</p>
|
||||
{% endif %}
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="formbutton" class="grid_1 suffix_1 omega">
|
||||
<input class="button green" type="submit" value="Submit">
|
||||
</div>
|
||||
</form>
|
||||
</p>
|
||||
{% else %}
|
||||
<p> </p>
|
||||
|
||||
@@ -154,7 +154,7 @@ urlpatterns = [
|
||||
url(r'^workout/(?P<id>\d+)/export/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.workout_edit_view),
|
||||
url(r'^workout/(?P<id>\d+)/edit/c/(?P<message>.+.*)$',views.workout_edit_view),
|
||||
url(r'^workout/(?P<id>\d+)/edit/s/(?P<successmessage>.+.*)$',views.workout_edit_view),
|
||||
url(r'^workout/(\d+)/edit$',views.workout_edit_view),
|
||||
url(r'^workout/(?P<id>\d+)/edit$',views.workout_edit_view),
|
||||
url(r'^workout/(?P<id>\d+)/advanced/c/(?P<message>.+.*)$',views.workout_advanced_view),
|
||||
url(r'^workout/(?P<id>\d+)/advanced/s/(?P<successmessage>.+.*)$',views.workout_advanced_view),
|
||||
url(r'^workout/(?P<id>\d+)/geeky$',views.workout_geeky_view),
|
||||
|
||||
573
rowers/views.py
573
rowers/views.py
@@ -67,13 +67,8 @@ from shutil import copyfile
|
||||
from rowingdata import rower as rrower
|
||||
from rowingdata import main as rmain
|
||||
from rowingdata import rowingdata as rrdata
|
||||
from rowingdata import TCXParser,RowProParser,ErgDataParser,TCXParserNoHR
|
||||
from rowingdata import BoatCoachParser,RowPerfectParser,BoatCoachAdvancedParser
|
||||
from rowingdata import MysteryParser
|
||||
from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser
|
||||
from rowingdata import SpeedCoach2Parser,FITParser,fitsummarydata
|
||||
from rowingdata import make_cumvalues
|
||||
from rowingdata import summarydata,get_file_type
|
||||
from rowingdata import summarydata
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
@@ -451,69 +446,27 @@ def add_workout_from_strokedata(user,importid,data,strokedata,
|
||||
compression='gzip')
|
||||
|
||||
|
||||
# make workout
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
r.pw_tr,r.pw_an])/r.ftp
|
||||
|
||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||
hrut1=r.ut1,hrat=r.at,
|
||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
||||
powerperc=powerperc,
|
||||
powerzones=r.powerzones,
|
||||
)
|
||||
row = rdata(csvfilename,rower=rr)
|
||||
|
||||
averagehr = row.df[' HRCur (bpm)'].mean()
|
||||
maxhr = row.df[' HRCur (bpm)'].max()
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
|
||||
|
||||
# with Concept2
|
||||
if source=='c2':
|
||||
try:
|
||||
totaldist = data['distance']
|
||||
totaltime = data['time']/10.
|
||||
except KeyError:
|
||||
pass
|
||||
totaldist = 0
|
||||
totaltime = 0
|
||||
else:
|
||||
totaldist = 0
|
||||
totaltime = 0
|
||||
|
||||
id,message = dataprep.save_workout_database(csvfilename,r,
|
||||
workouttype=workouttype,
|
||||
title=title,notes=comments,
|
||||
totaldist=totaldist,
|
||||
totaltime=totaltime)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
summary = row.summary()
|
||||
summary += '\n'
|
||||
summary += row.intervalstats()
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
# check for duplicate start times
|
||||
ws = Workout.objects.filter(starttime=workoutstarttime,
|
||||
user=r)
|
||||
if (len(ws) != 0):
|
||||
warnings.warn("Probably a duplicate workout",UserWarning)
|
||||
|
||||
# Create the Workout object
|
||||
w = Workout(user=r,name=title,
|
||||
date=workoutdate,workouttype=workouttype,
|
||||
duration=duration,distance=totaldist,
|
||||
weightcategory=r.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=csvfilename,notes=comments,
|
||||
uploadedtoc2=0,summary=summary,
|
||||
averagehr=averagehr,maxhr=maxhr,
|
||||
startdatetime=rowdatetime)
|
||||
w.save()
|
||||
|
||||
return w.id
|
||||
return id,message
|
||||
|
||||
# Create workout from SportTracks Data, which are slightly different
|
||||
# than Strava or Concept2 data
|
||||
@@ -582,7 +535,8 @@ def add_workout_from_stdata(user,importid,data):
|
||||
times_location = times_distance
|
||||
latcoord = np.zeros(len(times_distance))
|
||||
loncoord = np.zeros(len(times_distance))
|
||||
|
||||
if workouttype == 'water':
|
||||
workouttype = 'rower'
|
||||
|
||||
try:
|
||||
res = splitstdata(data['cadence'])
|
||||
@@ -668,89 +622,17 @@ def add_workout_from_stdata(user,importid,data):
|
||||
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
# auto smoothing
|
||||
pace = df[' Stroke500mPace (sec/500m)'].values
|
||||
velo = 500./pace
|
||||
|
||||
f = df['TimeStamp (sec)'].diff().mean()
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
|
||||
df['originalvelo'] = velo
|
||||
|
||||
if windowsize > 3 and windowsize<len(velo):
|
||||
velo2 = savgol_filter(velo,windowsize,3)
|
||||
else:
|
||||
velo2 = velo
|
||||
|
||||
velo3 = pd.Series(velo2)
|
||||
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
||||
velo3 = velo3.fillna(method='ffill')
|
||||
|
||||
pace2 = 500./abs(velo3)
|
||||
df[' Stroke500mPace (sec/500m)'] = pace2
|
||||
|
||||
df = df.fillna(0)
|
||||
|
||||
# end autosmoothing
|
||||
|
||||
csvfilename ='media/Import_'+str(importid)+'.csv'
|
||||
|
||||
res = df.to_csv(csvfilename+'.gz',index_label='index',
|
||||
compression='gzip')
|
||||
|
||||
# make workout
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
r.pw_tr,r.pw_an])/r.ftp
|
||||
id,message = dataprep.save_workout_database(csvfilename,r,
|
||||
workouttype=workouttype,
|
||||
title=title,
|
||||
notes=comments)
|
||||
|
||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||
hrut1=r.ut1,hrat=r.at,
|
||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
||||
powerperc=powerperc,powerzones=r.powerzones)
|
||||
row = rdata(csvfilename,rower=rr)
|
||||
|
||||
averagehr = row.df[' HRCur (bpm)'].mean()
|
||||
maxhr = row.df[' HRCur (bpm)'].max()
|
||||
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
|
||||
|
||||
|
||||
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)
|
||||
|
||||
|
||||
summary = row.summary()
|
||||
summary += '\n'
|
||||
summary += row.intervalstats()
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
# check for duplicate start times
|
||||
ws = Workout.objects.filter(starttime=workoutstarttime,
|
||||
user=r)
|
||||
if (len(ws) != 0):
|
||||
print "Warning: This workout probably already exists in the database"
|
||||
|
||||
w = Workout(user=r,name=title,
|
||||
date=workoutdate,workouttype=workouttype,
|
||||
duration=duration,distance=totaldist,
|
||||
weightcategory=r.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=csvfilename,notes=comments,
|
||||
uploadedtoc2=0,summary=summary,
|
||||
averagehr=averagehr,maxhr=maxhr,
|
||||
startdatetime=rowdatetime)
|
||||
w.save()
|
||||
|
||||
return w.id
|
||||
return (id,message)
|
||||
|
||||
# Checks if user has Concept2 tokens, resets tokens if they are
|
||||
# expired.
|
||||
@@ -765,7 +647,7 @@ def c2_open(user):
|
||||
if res[0] != None:
|
||||
thetoken = res[0]
|
||||
else:
|
||||
thetoken = r.c2token
|
||||
raise C2NoTokenError("User has no token")
|
||||
else:
|
||||
thetoken = r.c2token
|
||||
|
||||
@@ -3933,12 +3815,23 @@ def workout_getstravaworkout_view(request,stravaid):
|
||||
def workout_getstravaworkout_view(request,stravaid):
|
||||
res = stravastuff.get_strava_workout(request.user,stravaid)
|
||||
strokedata = res[1]
|
||||
data = res[0]
|
||||
data = res[0]
|
||||
id,message = add_workout_from_strokedata(request.user,stravaid,data,strokedata,
|
||||
source='strava')
|
||||
w = Workout.objects.get(id=id)
|
||||
w.uploadedtostrava=stravaid
|
||||
w.save()
|
||||
w.save()
|
||||
if message:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'message':message,
|
||||
'id':id,
|
||||
})
|
||||
else:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@@ -3947,11 +3840,21 @@ def workout_getsporttracksworkout_view(request,sporttracksid):
|
||||
def workout_getsporttracksworkout_view(request,sporttracksid):
|
||||
res = sporttracksstuff.get_sporttracks_workout(request.user,sporttracksid)
|
||||
data = res.json()
|
||||
|
||||
|
||||
id,message = add_workout_from_stdata(request.user,sporttracksid,data)
|
||||
w = Workout.objects.get(id=id)
|
||||
w.uploadedtosporttracks=sporttracksid
|
||||
w.save()
|
||||
w.save()
|
||||
if message:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
'message':message,
|
||||
})
|
||||
else:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@@ -3987,7 +3890,7 @@ def workout_getc2workout_view(request,c2id):
|
||||
# We have stroke data
|
||||
if res2.status_code == 200:
|
||||
strokedata = pd.DataFrame.from_dict(res2.json()['data'])
|
||||
# create the workout
|
||||
# create the workout
|
||||
id,message = add_workout_from_strokedata(request.user,c2id,data,strokedata,
|
||||
source='c2')
|
||||
w = Workout.objects.get(id=id)
|
||||
@@ -4022,7 +3925,18 @@ def workout_getc2workout_view(request,c2id):
|
||||
|
||||
rowdata.write_csv(w.csvfilename,gzip=True)
|
||||
dataprep.update_strokedata(w.id,rowdata.df)
|
||||
|
||||
|
||||
if message:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'message':message,
|
||||
'id':id,
|
||||
})
|
||||
else:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
@@ -4053,6 +3967,7 @@ def workout_getc2workout_view(request,c2id):
|
||||
|
||||
# This is the main view for processing uploaded files
|
||||
@login_required()
|
||||
def workout_upload_view(request,message=""):
|
||||
r = Rower.objects.get(user=request.user)
|
||||
if request.method == 'POST':
|
||||
form = DocumentsForm(request.POST,request.FILES)
|
||||
@@ -4071,282 +3986,81 @@ def workout_upload_view(request,message=""):
|
||||
|
||||
f1 = res[0] # file name
|
||||
f2 = res[1] # file name incl media directory
|
||||
|
||||
# get file type (ErgData, NK, BoatCoach, etc
|
||||
fileformat = get_file_type(f2)
|
||||
if len(fileformat)==3 and fileformat[0]=='zip':
|
||||
f_to_be_deleted = f2
|
||||
with zipfile.ZipFile(f2) as z:
|
||||
# for now, we're getting only the first file
|
||||
# from the NK zip file (issue #69 on bitbucket)
|
||||
f2 = z.extract(z.namelist()[0],path='media/')
|
||||
fileformat = fileformat[2]
|
||||
|
||||
|
||||
# Some people try to upload Concept2 logbook summaries
|
||||
if fileformat == 'c2log':
|
||||
os.remove(f2)
|
||||
|
||||
id,message = dataprep.new_workout_from_file(r,f2,
|
||||
workouttype=workouttype,
|
||||
title = t,
|
||||
notes='')
|
||||
if not id:
|
||||
url = reverse(workout_upload_view,
|
||||
args=[str(message)])
|
||||
response = HttpResponseRedirect(url)
|
||||
return response
|
||||
|
||||
# Some people try to upload RowPro summary logs
|
||||
if fileformat == 'rowprolog':
|
||||
os.remove(f2)
|
||||
message = "This RowPro logbook summary does not contain stroke data. Please use the Stroke Data CSV file for the individual workout in your log."
|
||||
url = reverse(workout_upload_view,
|
||||
args=[str(message)])
|
||||
response = HttpResponseRedirect(url)
|
||||
|
||||
else:
|
||||
if message:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
'message':message,
|
||||
})
|
||||
else:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
})
|
||||
|
||||
# Sometimes people try an unsupported file type.
|
||||
# Send an email to info@rowsandall.com with the file attached
|
||||
# for me to check if it is a bug, or a new file type
|
||||
# worth supporting
|
||||
if fileformat == 'unknown':
|
||||
message = "We couldn't recognize the file type"
|
||||
url = reverse(workout_upload_view,
|
||||
args=[str(message)])
|
||||
response = HttpResponseRedirect(url)
|
||||
if settings.DEBUG:
|
||||
res = handle_sendemail_unrecognized.delay(f2,
|
||||
|
||||
response = HttpResponseRedirect(url)
|
||||
w = Workout.objects.get(id=id)
|
||||
|
||||
else:
|
||||
res = queuehigh.enqueue(handle_sendemail_unrecognized,
|
||||
f2,request.user.email)
|
||||
|
||||
return response
|
||||
|
||||
summary = ''
|
||||
# handle non-Painsled by converting it to painsled
|
||||
# compatible CSV
|
||||
try:
|
||||
if (fileformat != 'csv'):
|
||||
# handle RowPro:
|
||||
if (fileformat == 'rp'):
|
||||
row = RowProParser(f2)
|
||||
# handle TCX
|
||||
if (fileformat == 'tcx'):
|
||||
row = TCXParser(f2)
|
||||
|
||||
# handle Mystery
|
||||
if (fileformat == 'mystery'):
|
||||
row = MysteryParser(f2)
|
||||
|
||||
# handle RowPerfect
|
||||
if (fileformat == 'rowperfect3'):
|
||||
row = RowPerfectParser(f2)
|
||||
|
||||
# handle TCX no HR
|
||||
if (fileformat == 'tcxnohr'):
|
||||
row = TCXParserNoHR(f2)
|
||||
|
||||
# handle ErgData
|
||||
if (fileformat == 'ergdata'):
|
||||
row = ErgDataParser(f2)
|
||||
|
||||
# handle Mike
|
||||
if (fileformat == 'bcmike'):
|
||||
row = BoatCoachAdvancedParser(f2)
|
||||
|
||||
# handle BoatCoach
|
||||
if (fileformat == 'boatcoach'):
|
||||
row = BoatCoachParser(f2)
|
||||
|
||||
# handle painsled desktop
|
||||
if (fileformat == 'painsleddesktop'):
|
||||
row = painsledDesktopParser(f2)
|
||||
|
||||
# handle speed coach GPS
|
||||
if (fileformat == 'speedcoach'):
|
||||
row = speedcoachParser(f2)
|
||||
|
||||
# handle speed coach GPS 2
|
||||
if (fileformat == 'speedcoach2'):
|
||||
row = SpeedCoach2Parser(f2)
|
||||
try:
|
||||
summary = row.allstats()
|
||||
except:
|
||||
pass
|
||||
|
||||
# handle ErgStick
|
||||
if (fileformat == 'ergstick'):
|
||||
row = ErgStickParser(f2)
|
||||
|
||||
# handle FIT
|
||||
if (fileformat == 'fit'):
|
||||
row = FITParser(f2)
|
||||
# The FIT files have nice lap/split summaries
|
||||
# so we make use of it
|
||||
s = fitsummarydata(f2)
|
||||
s.setsummary()
|
||||
summary = s.summarytext
|
||||
|
||||
# Save the Painsled compatible CSV file and delete
|
||||
# the uploaded file
|
||||
f_to_be_deleted = f2
|
||||
# should delete file
|
||||
f2 = f2[:-4]+'o.csv'
|
||||
row.write_csv(f2,gzip=True)
|
||||
|
||||
try:
|
||||
os.remove(f_to_be_deleted)
|
||||
except:
|
||||
os.remove(f_to_be_deleted+'.gz')
|
||||
|
||||
|
||||
if (make_plot):
|
||||
imagename = f1[:-4]+'.png'
|
||||
fullpathimagename = 'static/plots/'+imagename
|
||||
u = request.user
|
||||
r = Rower.objects.get(user=request.user)
|
||||
r = Rower.objects.get(user=request.user)
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
r.pw_tr,r.pw_an])/r.ftp
|
||||
|
||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||
hrut1=r.ut1,hrat=r.at,
|
||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
||||
powerperc=powerperc,powerzones=r.powerzones)
|
||||
row = rdata(f2,rower=rr)
|
||||
if row == 0:
|
||||
|
||||
hrpwrdata = {
|
||||
'hrmax':r.max,
|
||||
'hrut2':r.ut2,
|
||||
'hrut1':r.ut1,
|
||||
'hrat':r.at,
|
||||
'hrtr':r.tr,
|
||||
'hran':r.an,
|
||||
'ftp':r.ftp,
|
||||
'powerperc':serialize_list(powerperc),
|
||||
'powerzones':serialize_list(r.powerzones),
|
||||
}
|
||||
|
||||
# auto smoothing
|
||||
pace = row.df[' Stroke500mPace (sec/500m)'].values
|
||||
|
||||
# make plot - asynchronous task
|
||||
plotnrs = {
|
||||
'timeplot':1,
|
||||
'distanceplot':2,
|
||||
'pieplot':3,
|
||||
}
|
||||
|
||||
f = row.df['TimeStamp (sec)'].diff().mean()
|
||||
windowsize = 2*(int(10./(f)))+1
|
||||
if not 'originalvelo' in row.df:
|
||||
|
||||
plotnr = plotnrs[plottype]
|
||||
if (workouttype=='water'):
|
||||
plotnr = plotnr+3
|
||||
|
||||
if windowsize > 3 and windowsize<len(velo):
|
||||
|
||||
|
||||
if settings.DEBUG:
|
||||
res = handle_makeplot.delay(f1,f2,t,
|
||||
hrpwrdata,plotnr,
|
||||
imagename)
|
||||
else:
|
||||
velo2 = velo
|
||||
|
||||
velo3 = pd.Series(velo2)
|
||||
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
||||
velo3 = velo3.fillna(method='ffill')
|
||||
|
||||
pace2 = 500./abs(velo3)
|
||||
|
||||
row.df[' Stroke500mPace (sec/500m)'] = pace2
|
||||
|
||||
row.df = row.df.fillna(0)
|
||||
|
||||
row.write_csv(f2,gzip=True)
|
||||
try:
|
||||
os.remove(f2)
|
||||
except:
|
||||
pass
|
||||
|
||||
# recalculate power data
|
||||
if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides':
|
||||
try:
|
||||
row.erg_recalculatepower()
|
||||
row.write_csv(f2,gzip=True)
|
||||
except:
|
||||
pass
|
||||
|
||||
if fileformat != 'fit' and summary == '':
|
||||
summary = row.summary()
|
||||
summary += '\n'
|
||||
summary += row.intervalstats_painsled()
|
||||
|
||||
averagehr = row.df[' HRCur (bpm)'].mean()
|
||||
maxhr = row.df[' HRCur (bpm)'].max()
|
||||
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
else:
|
||||
res = queue.enqueue(handle_makeplot,f1,f2,
|
||||
t,hrpwrdata,
|
||||
plotnr,imagename)
|
||||
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutstartdatetime = thetimezone.localize(row.rowdatetime).astimezone(utc)
|
||||
|
||||
# check for duplicate start times
|
||||
r = Rower.objects.get(user=request.user)
|
||||
|
||||
ws = Workout.objects.filter(starttime=workoutstarttime,
|
||||
user=r)
|
||||
if (len(ws) != 0):
|
||||
message = "Warning: This workout probably already exists in the database"
|
||||
|
||||
w = Workout(user=r,name=t,date=workoutdate,
|
||||
workouttype=workouttype,
|
||||
duration=duration,distance=totaldist,
|
||||
weightcategory=r.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=f2,notes=notes,summary=summary,
|
||||
maxhr=maxhr,averagehr=averagehr,
|
||||
startdatetime=workoutstartdatetime)
|
||||
|
||||
w.save()
|
||||
|
||||
# put stroke data in database
|
||||
res = dataprep.dataprep(row.df,id=w.id,
|
||||
bands=True,barchart=True,
|
||||
otwpower=True,empower=True)
|
||||
|
||||
# Make Plot
|
||||
if (make_plot):
|
||||
imagename = f1[:-4]+'.png'
|
||||
fullpathimagename = 'static/plots/'+imagename
|
||||
u = request.user
|
||||
r = Rower.objects.get(user=request.user)
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
r.pw_tr,r.pw_an])/r.ftp
|
||||
|
||||
|
||||
hrpwrdata = {
|
||||
'hrmax':r.max,
|
||||
'hrut2':r.ut2,
|
||||
'hrut1':r.ut1,
|
||||
'hrat':r.at,
|
||||
'hrtr':r.tr,
|
||||
'hran':r.an,
|
||||
'ftp':r.ftp,
|
||||
'powerperc':serialize_list(powerperc),
|
||||
'powerzones':serialize_list(r.powerzones),
|
||||
}
|
||||
|
||||
# make plot - asynchronous task
|
||||
plotnrs = {
|
||||
'timeplot':1,
|
||||
'distanceplot':2,
|
||||
'pieplot':3,
|
||||
}
|
||||
|
||||
plotnr = plotnrs[plottype]
|
||||
if (workouttype=='water'):
|
||||
plotnr = plotnr+3
|
||||
|
||||
|
||||
if settings.DEBUG:
|
||||
res = handle_makeplot.delay(f1,f2,t,
|
||||
hrpwrdata,plotnr,
|
||||
imagename)
|
||||
else:
|
||||
res = queue.enqueue(handle_makeplot,f1,f2,
|
||||
t,hrpwrdata,
|
||||
plotnr,imagename)
|
||||
|
||||
|
||||
i = GraphImage(workout=w,
|
||||
creationdatetime=timezone.now(),
|
||||
filename=fullpathimagename)
|
||||
|
||||
i = GraphImage(workout=w,
|
||||
creationdatetime=timezone.now(),
|
||||
filename=fullpathimagename)
|
||||
i.save()
|
||||
|
||||
# upload to C2
|
||||
@@ -4355,7 +4069,6 @@ def workout_upload_view(request,message=""):
|
||||
thetoken = c2_open(request.user)
|
||||
except C2NoTokenError:
|
||||
return HttpResponseRedirect("/rowers/me/c2authorize/")
|
||||
try:
|
||||
try:
|
||||
c2userid = c2stuff.get_userid(thetoken)
|
||||
data = c2stuff.createc2workoutdata(w)
|
||||
@@ -4383,28 +4096,29 @@ def workout_upload_view(request,message=""):
|
||||
s= json.loads(response.text)
|
||||
c2id = s['data']['id']
|
||||
w.uploadedtoc2 = c2id
|
||||
w.save()
|
||||
|
||||
except:
|
||||
message = "C2 upload failed"
|
||||
url = reverse(workout_edit_view,
|
||||
w.save()
|
||||
except:
|
||||
message = "C2 upload failed"
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs={
|
||||
'message':message,
|
||||
'id':str(w.id),
|
||||
'id':str(w.id),
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# redirect to workout edit page
|
||||
url = "/rowers/workout/"+str(w.id)+"/edit"
|
||||
return HttpResponseRedirect(url)
|
||||
except:
|
||||
if settings.DEBUG:
|
||||
errorstring = str(sys.exc_info()[0])
|
||||
print errorstring
|
||||
|
||||
|
||||
url = reverse(workout_upload_view,
|
||||
args=[str(message)])
|
||||
|
||||
if message:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs={
|
||||
'message':message,
|
||||
'id':w.id,
|
||||
})
|
||||
|
||||
else:
|
||||
url = reverse(workout_edit_view,
|
||||
kwargs = {
|
||||
'id':w.id,
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
response = render(request,
|
||||
@@ -5367,21 +5081,35 @@ def team_leave_view(request,id=0):
|
||||
url = reverse(rower_teams_view)
|
||||
response = HttpResponseRedirect(url)
|
||||
return response
|
||||
|
||||
from rowers.forms import TeamInviteCodeForm
|
||||
|
||||
@login_required()
|
||||
def rower_teams_view(request,message='',successmessage=''):
|
||||
if request.method == 'POST':
|
||||
form = TeamInviteCodeForm(request.POST)
|
||||
if form.is_valid():
|
||||
code = form.cleaned_data['code']
|
||||
res,text = teams.process_invite_code(request.user,code)
|
||||
if res:
|
||||
successmessage = text
|
||||
else:
|
||||
message = text
|
||||
else:
|
||||
form = TeamInviteCodeForm()
|
||||
|
||||
r = Rower.objects.get(user=request.user)
|
||||
ts = Team.objects.filter(rower=r)
|
||||
myteams = Team.objects.filter(manager=request.user)
|
||||
otherteams = Team.objects.filter(private='open').exclude(rower=r).exclude(manager=request.user).order_by('name')
|
||||
teams.remove_expired_invites()
|
||||
|
||||
print "aap",otherteams
|
||||
|
||||
invites = TeamInvite.objects.filter(user=request.user)
|
||||
requests = TeamRequest.objects.filter(user=request.user)
|
||||
myrequests = TeamRequest.objects.filter(team__in=myteams)
|
||||
myinvites = TeamInvite.objects.filter(team__in=myteams)
|
||||
|
||||
print form
|
||||
|
||||
return render(request, 'teams.html',
|
||||
{
|
||||
@@ -5390,6 +5118,7 @@ def rower_teams_view(request,message='',successmessage=''):
|
||||
'invites':invites,
|
||||
'otherteams':otherteams,
|
||||
'requests':requests,
|
||||
'myrequests':myrequests,
|
||||
'form':form,
|
||||
'message':message,
|
||||
'successmessage':successmessage,
|
||||
|
||||
@@ -14,7 +14,9 @@ from settings import *
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),},
|
||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||
'HOST': 'localhost'
|
||||
},
|
||||
# 'TEST': {
|
||||
# 'CHARSET': 'utf8',
|
||||
# 'COLLATION': 'utf8_general_ci',
|
||||
|
||||
Reference in New Issue
Block a user