Merge branch 'feature/performancemanager' into develop
This commit is contained in:
+5
-1
@@ -1242,7 +1242,7 @@ def fetchcp(rower,theworkouts,table='cpdata'):
|
|||||||
def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
|
def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
|
||||||
avghr=None,avgpwr=None,avgspm=None,
|
avghr=None,avgpwr=None,avgspm=None,
|
||||||
rankingpiece = False,
|
rankingpiece = False,
|
||||||
duplicate=False,
|
duplicate=False,rpe=-1,
|
||||||
title='Manual entry',notes='',weightcategory='hwt',
|
title='Manual entry',notes='',weightcategory='hwt',
|
||||||
adaptiveclass='None'):
|
adaptiveclass='None'):
|
||||||
|
|
||||||
@@ -1351,6 +1351,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
workoutsource='unknown',
|
workoutsource='unknown',
|
||||||
notes='', totaldist=0, totaltime=0,
|
notes='', totaldist=0, totaltime=0,
|
||||||
rankingpiece=False,
|
rankingpiece=False,
|
||||||
|
rpe=-1,
|
||||||
duplicate=False,
|
duplicate=False,
|
||||||
summary='',
|
summary='',
|
||||||
makeprivate=False,
|
makeprivate=False,
|
||||||
@@ -1583,6 +1584,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
workoutsource=workoutsource,
|
workoutsource=workoutsource,
|
||||||
rankingpiece=rankingpiece,
|
rankingpiece=rankingpiece,
|
||||||
forceunit=forceunit,
|
forceunit=forceunit,
|
||||||
|
rpe=rpe,
|
||||||
csvfilename=f2, notes=notes, summary=summary,
|
csvfilename=f2, notes=notes, summary=summary,
|
||||||
maxhr=maxhr, averagehr=averagehr,
|
maxhr=maxhr, averagehr=averagehr,
|
||||||
startdatetime=workoutstartdatetime,
|
startdatetime=workoutstartdatetime,
|
||||||
@@ -1810,6 +1812,7 @@ def new_workout_from_file(r, f2,
|
|||||||
workoutsource=None,
|
workoutsource=None,
|
||||||
title='Workout',
|
title='Workout',
|
||||||
boattype='1x',
|
boattype='1x',
|
||||||
|
rpe=-1,
|
||||||
makeprivate=False,
|
makeprivate=False,
|
||||||
notes='',
|
notes='',
|
||||||
uploadoptions={'boattype':'1x','workouttype':'rower'}):
|
uploadoptions={'boattype':'1x','workouttype':'rower'}):
|
||||||
@@ -1944,6 +1947,7 @@ def new_workout_from_file(r, f2,
|
|||||||
dosummary=dosummary,
|
dosummary=dosummary,
|
||||||
workoutsource=workoutsource,
|
workoutsource=workoutsource,
|
||||||
summary=summary,
|
summary=summary,
|
||||||
|
rpe=rpe,
|
||||||
inboard=inboard, oarlength=oarlength,
|
inboard=inboard, oarlength=oarlength,
|
||||||
title=title,
|
title=title,
|
||||||
forceunit='N',
|
forceunit='N',
|
||||||
|
|||||||
@@ -13,6 +13,20 @@ from rowers.mytypes import otwtypes,otetypes,rowtypes
|
|||||||
#p0 = [500,350,10,8000]
|
#p0 = [500,350,10,8000]
|
||||||
p0 = [190,200,33,16000]
|
p0 = [190,200,33,16000]
|
||||||
|
|
||||||
|
# RPE to TSS
|
||||||
|
rpetotss = {
|
||||||
|
1:20,
|
||||||
|
2:30,
|
||||||
|
3:40,
|
||||||
|
4:50,
|
||||||
|
5:60,
|
||||||
|
6:70,
|
||||||
|
7:80,
|
||||||
|
8:100,
|
||||||
|
9:120,
|
||||||
|
10:140,
|
||||||
|
}
|
||||||
|
|
||||||
def updatecp(delta,cpvalues,r,workouttype='water'):
|
def updatecp(delta,cpvalues,r,workouttype='water'):
|
||||||
if workouttype in otwtypes:
|
if workouttype in otwtypes:
|
||||||
p0 = r.p0
|
p0 = r.p0
|
||||||
|
|||||||
+7
-1
@@ -245,17 +245,23 @@ class StandardsForm(forms.Form):
|
|||||||
|
|
||||||
# The form used for uploading files
|
# The form used for uploading files
|
||||||
class DocumentsForm(forms.Form):
|
class DocumentsForm(forms.Form):
|
||||||
|
rpechoices = Workout.rpechoices
|
||||||
|
rpechoices = tuple([(-1,'---')]+list(rpechoices))
|
||||||
title = forms.CharField(required=False)
|
title = forms.CharField(required=False)
|
||||||
file = forms.FileField(required=False,
|
file = forms.FileField(required=False,
|
||||||
validators=[validate_file_extension])
|
validators=[validate_file_extension])
|
||||||
|
|
||||||
workouttype = forms.ChoiceField(required=True,
|
workouttype = forms.ChoiceField(required=True,
|
||||||
choices=Workout.workouttypes)
|
choices=Workout.workouttypes,
|
||||||
|
label='Workout Type')
|
||||||
|
|
||||||
boattype = forms.ChoiceField(required=True,
|
boattype = forms.ChoiceField(required=True,
|
||||||
choices=mytypes.boattypes,
|
choices=mytypes.boattypes,
|
||||||
label = "Boat Type")
|
label = "Boat Type")
|
||||||
|
|
||||||
|
rpe = forms.ChoiceField(required=False,
|
||||||
|
choices=rpechoices,
|
||||||
|
label='Rate of Perceived Exertion',initial=-1)
|
||||||
|
|
||||||
notes = forms.CharField(required=False,
|
notes = forms.CharField(required=False,
|
||||||
widget=forms.Textarea)
|
widget=forms.Textarea)
|
||||||
|
|||||||
+43
-25
@@ -97,7 +97,7 @@ import rowers.c2stuff as c2stuff
|
|||||||
from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima,get_yaxminima,get_yaxmaxima
|
from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima,get_yaxminima,get_yaxmaxima
|
||||||
|
|
||||||
from rowers.utils import lbstoN
|
from rowers.utils import lbstoN
|
||||||
from rowers.datautils import p0
|
from rowers.datautils import p0,rpetotss
|
||||||
import rowers.datautils as datautils
|
import rowers.datautils as datautils
|
||||||
|
|
||||||
from pandas.core.groupby.groupby import DataError
|
from pandas.core.groupby.groupby import DataError
|
||||||
@@ -1650,18 +1650,30 @@ def getfatigues(
|
|||||||
if metricchoice == 'rscore':
|
if metricchoice == 'rscore':
|
||||||
factor = 2.0
|
factor = 2.0
|
||||||
|
|
||||||
for i in range(nrdays):
|
for i in range(nrdays+1):
|
||||||
date = startdate+datetime.timedelta(days=i)
|
date = startdate+datetime.timedelta(days=i)
|
||||||
ws = Workout.objects.filter(user=user.rower,date=date,duplicate=False)
|
ws = Workout.objects.filter(user=user.rower,date=date,duplicate=False)
|
||||||
weight = 0
|
weight = 0
|
||||||
for w in ws:
|
for w in ws:
|
||||||
weight += factor*getattr(w,metricchoice)
|
if getattr(w,metricchoice) > 0:
|
||||||
if getattr(w,metricchoice) == 0:
|
weight += factor*getattr(w,metricchoice)
|
||||||
if metricchoice == 'rscore' and w.hrtss != 0:
|
if getattr(w,metricchoice) <= 0:
|
||||||
|
if metricchoice == 'rscore' and w.hrtss > 0:
|
||||||
weight+= factor*w.hrtss
|
weight+= factor*w.hrtss
|
||||||
else:
|
elif metricchoice == 'rscore' and w.hrtss <= 0:
|
||||||
trimp,hrtss = dataprep.workout_trimp(w)
|
trimp,hrtss = dataprep.workout_trimp(w)
|
||||||
rscore,normp = dataprep.workout_rscore(w)
|
rscore,normp = dataprep.workout_rscore(w)
|
||||||
|
if w.rpe and w.rpe > 0:
|
||||||
|
dd = 3600*w.duration.hour+60*w.duration.minute+w.duration.second
|
||||||
|
dd = dd/3600
|
||||||
|
weight += factor*rpetotss[w.rpe]*dd
|
||||||
|
elif metricchoice == 'trimp' and w.trimp <= 0:
|
||||||
|
trimp,hrtss = dataprep.workout_trimp(w)
|
||||||
|
rscore,normp = dataprep.workout_rscore(w)
|
||||||
|
if w.rpe and w.rpe > 0:
|
||||||
|
dd = 3600*w.duration.hour+60*w.duration.minute+w.duration.second
|
||||||
|
dd = dd/3600
|
||||||
|
weight += 2*rpetotss[w.rpe]*dd
|
||||||
|
|
||||||
impulses.append(weight)
|
impulses.append(weight)
|
||||||
|
|
||||||
@@ -1680,6 +1692,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
|||||||
metricchoice='trimp',doform=False,dofatigue=False):
|
metricchoice='trimp',doform=False,dofatigue=False):
|
||||||
|
|
||||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
TOOLS2 = 'box_zoom,hover'
|
||||||
|
|
||||||
|
|
||||||
fatigues = []
|
fatigues = []
|
||||||
@@ -1713,7 +1726,9 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
|||||||
'impulse':impulses,
|
'impulse':impulses,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
endfitness = fitnesses[-1]
|
||||||
|
endfatigue = fatigues[-1]
|
||||||
|
endform = endfitness-endfatigue
|
||||||
|
|
||||||
if modelchoice == 'banister':
|
if modelchoice == 'banister':
|
||||||
df['fatigue'] = k2*df['fatigue']
|
df['fatigue'] = k2*df['fatigue']
|
||||||
@@ -1777,18 +1792,18 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
|||||||
fitlabel = 'PTE (fitness)'
|
fitlabel = 'PTE (fitness)'
|
||||||
fatiguelabel = 'NTE (fatigue)'
|
fatiguelabel = 'NTE (fatigue)'
|
||||||
formlabel = 'Performance'
|
formlabel = 'Performance'
|
||||||
rightaxlabel = 'NTE'
|
rightaxlabel = 'Performance'
|
||||||
if doform:
|
if dofatigue:
|
||||||
yaxlabel = 'PTE/Performance'
|
yaxlabel = 'PTE/NTE'
|
||||||
else:
|
else:
|
||||||
yaxlabel = 'PTE'
|
yaxlabel = 'PTE'
|
||||||
else:
|
else:
|
||||||
fitlabel = 'Fitness'
|
fitlabel = 'Fitness'
|
||||||
fatiguelabel = 'Fatigue'
|
fatiguelabel = 'Fatigue'
|
||||||
formlabel = 'Freshness'
|
formlabel = 'Freshness'
|
||||||
rightaxlabel = 'Fatigue'
|
rightaxlabel = 'Freshness'
|
||||||
if doform:
|
if dofatigue:
|
||||||
yaxlabel = 'Fitness/Freshness'
|
yaxlabel = 'Fitness/Fatigue'
|
||||||
else:
|
else:
|
||||||
yaxlabel = 'Fitness'
|
yaxlabel = 'Fitness'
|
||||||
|
|
||||||
@@ -1829,13 +1844,6 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
|||||||
|
|
||||||
plot.legend.location = "top_left"
|
plot.legend.location = "top_left"
|
||||||
|
|
||||||
#plot.xaxis.formatter = DatetimeTickFormatter(
|
|
||||||
# days=["%d %B %Y"],
|
|
||||||
# months=["%d %B %Y"],
|
|
||||||
# years=["%d %B %Y"],
|
|
||||||
# )
|
|
||||||
|
|
||||||
#plot.xaxis.major_label_orientation = pi/4
|
|
||||||
plot.sizing_mode = 'scale_both'
|
plot.sizing_mode = 'scale_both'
|
||||||
|
|
||||||
#plot.y_range = Range1d(0,1.5*max(df['testpower']))
|
#plot.y_range = Range1d(0,1.5*max(df['testpower']))
|
||||||
@@ -1854,19 +1862,26 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
|||||||
|
|
||||||
hover = plot.select(dict(type=HoverTool))
|
hover = plot.select(dict(type=HoverTool))
|
||||||
|
|
||||||
|
linked_crosshair = CrosshairTool(dimensions='height')
|
||||||
|
|
||||||
hover.tooltips = OrderedDict([
|
hover.tooltips = OrderedDict([
|
||||||
#(legend_label,'@testpower'),
|
#(legend_label,'@testpower'),
|
||||||
('Date','@fdate'),
|
('Date','@fdate'),
|
||||||
(fitlabel,'@fitness'),
|
(fitlabel,'@fitness{int}'),
|
||||||
(fatiguelabel,'@fatigue'),
|
(fatiguelabel,'@fatigue{int}'),
|
||||||
(formlabel,'@form')
|
(formlabel,'@form{int}'),
|
||||||
|
('Impulse','@impulse{int}')
|
||||||
])
|
])
|
||||||
|
|
||||||
plot2 = Figure(tools=TOOLS,x_axis_type='datetime',
|
|
||||||
|
|
||||||
|
plot2 = Figure(tools=TOOLS2,x_axis_type='datetime',
|
||||||
plot_width=900,plot_height=150,
|
plot_width=900,plot_height=150,
|
||||||
toolbar_location=None,
|
toolbar_location=None,
|
||||||
toolbar_sticky=False)
|
toolbar_sticky=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
plot2.x_range = xrange
|
plot2.x_range = xrange
|
||||||
plot2.y_range = Range1d(0,df['impulse'].max())
|
plot2.y_range = Range1d(0,df['impulse'].max())
|
||||||
|
|
||||||
@@ -1876,6 +1891,9 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
|||||||
plot2.yaxis.axis_label = 'Impulse'
|
plot2.yaxis.axis_label = 'Impulse'
|
||||||
plot2.xaxis.axis_label = 'Date'
|
plot2.xaxis.axis_label = 'Date'
|
||||||
|
|
||||||
|
plot.add_tools(linked_crosshair)
|
||||||
|
plot2.add_tools(linked_crosshair)
|
||||||
|
|
||||||
layout = layoutcolumn([plot,plot2])
|
layout = layoutcolumn([plot,plot2])
|
||||||
layout.sizing_mode = 'stretch_both'
|
layout.sizing_mode = 'stretch_both'
|
||||||
|
|
||||||
@@ -1892,7 +1910,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return [script,div]
|
return [script,div,endfitness,endfatigue,endform]
|
||||||
|
|
||||||
|
|
||||||
def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
|
def fitnessfit_chart(workouts,user,workoutmode='water',startdate=None,
|
||||||
|
|||||||
+28
-3
@@ -881,11 +881,17 @@ class Rower(models.Model):
|
|||||||
ep3 = models.FloatField(default=1.0,verbose_name="erg CP p4")
|
ep3 = models.FloatField(default=1.0,verbose_name="erg CP p4")
|
||||||
ecpratio = models.FloatField(default=1.0,verbose_name="erg CP fit ratio")
|
ecpratio = models.FloatField(default=1.0,verbose_name="erg CP fit ratio")
|
||||||
|
|
||||||
cprange = models.IntegerField(default=42,verbose_name="Range for calculation breakthrough workouts and fitness (CP)",
|
cprange = models.IntegerField(default=42,verbose_name="Range for calculation of breakthrough workouts and fitness (CP)",
|
||||||
choices=cppresets)
|
choices=cppresets)
|
||||||
|
|
||||||
otwslack = models.IntegerField(default=0,verbose_name="OTW Power slack")
|
otwslack = models.IntegerField(default=0,verbose_name="OTW Power slack")
|
||||||
|
|
||||||
|
# performance manager stuff
|
||||||
|
kfit = models.IntegerField(default=42,verbose_name='Fitness Time Decay Constant (days)')
|
||||||
|
kfatigue = models.IntegerField(default=7,verbose_name='Fatigue Time Decay Constant (days)')
|
||||||
|
showfit = models.BooleanField(default=False)
|
||||||
|
showfresh = models.BooleanField(default=False)
|
||||||
|
|
||||||
pw_ut2 = models.IntegerField(default=124,verbose_name="UT2 Power")
|
pw_ut2 = models.IntegerField(default=124,verbose_name="UT2 Power")
|
||||||
pw_ut1 = models.IntegerField(default=171,verbose_name="UT1 Power")
|
pw_ut1 = models.IntegerField(default=171,verbose_name="UT1 Power")
|
||||||
pw_at = models.IntegerField(default=203,verbose_name="AT Power")
|
pw_at = models.IntegerField(default=203,verbose_name="AT Power")
|
||||||
@@ -2898,6 +2904,19 @@ class Workout(models.Model):
|
|||||||
privacychoices = mytypes.privacychoices
|
privacychoices = mytypes.privacychoices
|
||||||
adaptivetypes = mytypes.adaptivetypes
|
adaptivetypes = mytypes.adaptivetypes
|
||||||
boatbrands = mytypes.boatbrands
|
boatbrands = mytypes.boatbrands
|
||||||
|
rpechoices = (
|
||||||
|
(0,'Not Specified'),
|
||||||
|
(1,'1 Very Easy (a walk in the park)'), # 20 TSS / hour
|
||||||
|
(2,'2 Easy (You breathe normally, it feels comfortable)'), # 30 TSS / hour
|
||||||
|
(3,'3 Somewhat easy (You can talk easily but did you notice the beautiful clouds?)'),
|
||||||
|
(4,'4 Moderate (You can talk in short spurts, breathing more labored, this feels just right)'), # 50 TSS/hour
|
||||||
|
(5,"5 (It's not that painful, you just don't want to be here all day.)"),
|
||||||
|
(6,'6 Somewhat Hard (You can say a few words if you need to)'), # 70 TSS / hour
|
||||||
|
(7,'7 Vigorous (This is starting to get painful)'),
|
||||||
|
(8,"8 Hard (You can barely talk, breathing heavily, hoping you won't have to this that long)"), # 100 TSS / hour
|
||||||
|
(9,'9 Very Hard (My goodness, please make it stop)'), # 120 TSS / hour
|
||||||
|
(10,'10 Max Effort (You can barely remember your name, you would rather rip out your toenails than go through this)') # 140 TSS / hour
|
||||||
|
)
|
||||||
|
|
||||||
user = models.ForeignKey(Rower,on_delete=models.CASCADE)
|
user = models.ForeignKey(Rower,on_delete=models.CASCADE)
|
||||||
team = models.ManyToManyField(Team,blank=True)
|
team = models.ManyToManyField(Team,blank=True)
|
||||||
@@ -2925,12 +2944,18 @@ class Workout(models.Model):
|
|||||||
distance = models.IntegerField(default=0,blank=True)
|
distance = models.IntegerField(default=0,blank=True)
|
||||||
duration = models.TimeField(blank=True)
|
duration = models.TimeField(blank=True)
|
||||||
dragfactor = models.IntegerField(default=0,blank=True)
|
dragfactor = models.IntegerField(default=0,blank=True)
|
||||||
|
|
||||||
|
# scores
|
||||||
trimp = models.IntegerField(default=-1,blank=True)
|
trimp = models.IntegerField(default=-1,blank=True)
|
||||||
rscore = models.IntegerField(default=-1,blank=True)
|
rscore = models.IntegerField(default=-1,blank=True)
|
||||||
hrtss = models.IntegerField(default=-1,blank=True)
|
hrtss = models.IntegerField(default=-1,blank=True)
|
||||||
normp = models.IntegerField(default=-1,blank=True)
|
normp = models.IntegerField(default=-1,blank=True)
|
||||||
normv = models.FloatField(default=-1,blank=True)
|
normv = models.FloatField(default=-1,blank=True)
|
||||||
normw = models.FloatField(default=-1,blank=True)
|
normw = models.FloatField(default=-1,blank=True)
|
||||||
|
goldmedalstandard = models.FloatField(default=-1,blank=True,verbose_name='Gold Medal Standard')
|
||||||
|
rpe = models.IntegerField(default=0,blank=True,choices=rpechoices,
|
||||||
|
verbose_name='Rate of Perceived Exertion')
|
||||||
|
|
||||||
weightcategory = models.CharField(
|
weightcategory = models.CharField(
|
||||||
default="hwt",
|
default="hwt",
|
||||||
max_length=10,
|
max_length=10,
|
||||||
@@ -2958,7 +2983,6 @@ class Workout(models.Model):
|
|||||||
inboard = models.FloatField(default=0.88)
|
inboard = models.FloatField(default=0.88)
|
||||||
oarlength = models.FloatField(default=2.89)
|
oarlength = models.FloatField(default=2.89)
|
||||||
|
|
||||||
|
|
||||||
notes = models.CharField(blank=True,null=True,max_length=1000)
|
notes = models.CharField(blank=True,null=True,max_length=1000)
|
||||||
summary = models.TextField(blank=True)
|
summary = models.TextField(blank=True)
|
||||||
privacy = models.CharField(default='visible',max_length=30,
|
privacy = models.CharField(default='visible',max_length=30,
|
||||||
@@ -3541,6 +3565,7 @@ class WorkoutForm(ModelForm):
|
|||||||
'dragfactor',
|
'dragfactor',
|
||||||
'weightcategory',
|
'weightcategory',
|
||||||
'adaptiveclass',
|
'adaptiveclass',
|
||||||
|
'rpe',
|
||||||
'notes',
|
'notes',
|
||||||
'rankingpiece',
|
'rankingpiece',
|
||||||
'duplicate',
|
'duplicate',
|
||||||
@@ -3618,7 +3643,7 @@ class RowerPowerForm(ModelForm):
|
|||||||
class RowerCPForm(ModelForm):
|
class RowerCPForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rower
|
model = Rower
|
||||||
fields = ['cprange']
|
fields = ['cprange','kfit','kfatigue']
|
||||||
|
|
||||||
# Form to set rower's Power zones, including test routines
|
# Form to set rower's Power zones, including test routines
|
||||||
# to enable consistency
|
# to enable consistency
|
||||||
|
|||||||
@@ -11,20 +11,29 @@
|
|||||||
|
|
||||||
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<!--
|
|
||||||
<li class="rounder">
|
<li class="rounder">
|
||||||
<h2>Performance Manager</h2>
|
<h2>Performance Manager</h2>
|
||||||
<a href="/rowers/performancemanager/">
|
<a href="/rowers/performancemanager/">
|
||||||
<div class="vignet">
|
<div class="vignet">
|
||||||
<img src="/static/img/perfmanager.png"
|
<img src="/static/img/PM.jpg"
|
||||||
alt="Performance Manager">
|
alt="Performance Manager">
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Manager Fitness, Fatigue and Freshness
|
Manage Fitness, Fatigue and Freshness
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
-->
|
<li class="rounder">
|
||||||
|
<h2>Critical Power</h2>
|
||||||
|
<a href="/rowers/user-analysis-select/cp/">
|
||||||
|
<div class="vignet">
|
||||||
|
<img src="/static/img/otwcp.png" alt="Critical Power">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<p>
|
||||||
|
Analyse power vs piece duration to make predictions.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
<li class="rounder">
|
<li class="rounder">
|
||||||
<h2>Compare Workouts</h2>
|
<h2>Compare Workouts</h2>
|
||||||
{% if team %}
|
{% if team %}
|
||||||
@@ -53,17 +62,6 @@
|
|||||||
Plot all strokes in a date range and analyze several parameters (Power, Pace, SPM, Heart Rate).
|
Plot all strokes in a date range and analyze several parameters (Power, Pace, SPM, Heart Rate).
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li class="rounder">
|
|
||||||
<h2>Histogram</h2>
|
|
||||||
<a href="/rowers/user-analysis-select/histo/">
|
|
||||||
<div class="vignet">
|
|
||||||
<img src="/static/img/histogram.png" alt="Power Histogram">
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<p>
|
|
||||||
Plot a histogram chart of one metric for all your strokes over a date range.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li class="rounder">
|
<li class="rounder">
|
||||||
<h2>Statistics</h2>
|
<h2>Statistics</h2>
|
||||||
<a href="/rowers/user-analysis-select/stats/">
|
<a href="/rowers/user-analysis-select/stats/">
|
||||||
@@ -98,17 +96,6 @@
|
|||||||
<p>
|
<p>
|
||||||
Select workouts and make X-Y charts of averages over various metrics
|
Select workouts and make X-Y charts of averages over various metrics
|
||||||
</p>
|
</p>
|
||||||
</li>
|
|
||||||
<li class="rounder">
|
|
||||||
<h2>Critical Power</h2>
|
|
||||||
<a href="/rowers/user-analysis-select/cp/">
|
|
||||||
<div class="vignet">
|
|
||||||
<img src="/static/img/otwcp.png" alt="Critical Power">
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<p>
|
|
||||||
Analyse power vs piece duration to make predictions.
|
|
||||||
</p>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="rounder">
|
<li class="rounder">
|
||||||
<h2>Power Progress</h2>
|
<h2>Power Progress</h2>
|
||||||
@@ -144,6 +131,17 @@
|
|||||||
<p>
|
<p>
|
||||||
Analyze your Concept2 ranking pieces over a date range and predict your pace on other pieces.
|
Analyze your Concept2 ranking pieces over a date range and predict your pace on other pieces.
|
||||||
</p>
|
</p>
|
||||||
|
</li>
|
||||||
|
<li class="rounder">
|
||||||
|
<h2>Histogram</h2>
|
||||||
|
<a href="/rowers/user-analysis-select/histo/">
|
||||||
|
<div class="vignet">
|
||||||
|
<img src="/static/img/histogram.png" alt="Power Histogram">
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
<p>
|
||||||
|
Plot a histogram chart of one metric for all your strokes over a date range.
|
||||||
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,16 @@
|
|||||||
<i class="fas fa-watch-fitness fa-fw"></i> Fitness
|
<i class="fas fa-watch-fitness fa-fw"></i> Fitness
|
||||||
</label>
|
</label>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li id="performancemanager">
|
||||||
|
<a href="/rowers/performancemanager/">
|
||||||
|
<i class="far fa-battery-bolt fa-fw"></i> Performance Manager
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li id="fitness-otecp">
|
||||||
|
<a href="/rowers/user-analysis-select/cp/">
|
||||||
|
<i class="fas fa-user-chart fa-fw"></i> CP Chart
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li id="compare">
|
<li id="compare">
|
||||||
{% if team %}
|
{% if team %}
|
||||||
<a href="/rowers/user-analysis-select/compare/team/{{ team.id }}/">
|
<a href="/rowers/user-analysis-select/compare/team/{{ team.id }}/">
|
||||||
@@ -41,11 +51,6 @@
|
|||||||
<a href="/rowers/fitness-progress/">
|
<a href="/rowers/fitness-progress/">
|
||||||
<i class="far fa-watch-fitness fa-fw"></i> Power Progress
|
<i class="far fa-watch-fitness fa-fw"></i> Power Progress
|
||||||
</a>
|
</a>
|
||||||
</li>
|
|
||||||
<li id="fitness-otecp">
|
|
||||||
<a href="/rowers/user-analysis-select/cp/">
|
|
||||||
<i class="fas fa-user-chart fa-fw"></i> CP Chart
|
|
||||||
</a>
|
|
||||||
</li>
|
</li>
|
||||||
<li id="fitness-ranking">
|
<li id="fitness-ranking">
|
||||||
<a href="/rowers/ote-bests2/">
|
<a href="/rowers/ote-bests2/">
|
||||||
|
|||||||
@@ -4,72 +4,75 @@
|
|||||||
|
|
||||||
{% block title %}Rowsandall Fitness Progress {% endblock %}
|
{% block title %}Rowsandall Fitness Progress {% endblock %}
|
||||||
|
|
||||||
{% block main %}
|
{% block scripts %}
|
||||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
<script type='text/javascript'
|
||||||
|
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||||
|
</script>
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
|
||||||
|
|
||||||
// Get the form fields and hidden div
|
function submit_form() {
|
||||||
var checkbox = $("#id_water");
|
console.log("form changed");
|
||||||
var hidden = $("#id_waterboattype");
|
var frm = $("#performanceform");
|
||||||
|
|
||||||
|
var data = new FormData(frm[0]);
|
||||||
|
|
||||||
// Hide the fields.
|
$.ajax({
|
||||||
// Use JS to do this in case the user doesn't have JS
|
url:"/rowers/performancemanager/user/{{ rower.user.id }}/",
|
||||||
// enabled.
|
type: "POST",
|
||||||
|
contentType: false,
|
||||||
|
processData: false,
|
||||||
|
data: data,
|
||||||
|
dataType: 'json',
|
||||||
|
|
||||||
hidden.hide();
|
success: function(data) {
|
||||||
|
console.log(data);
|
||||||
|
// var parsedJSON = $.parseJSON(data); //
|
||||||
// Setup an event listener for when the state of the
|
$("#id_script").replaceWith('<div id="id_script">'+data.script+'</d'+'iv>');
|
||||||
// checkbox changes.
|
$("#id_chart").replaceWith('<div id="id_chart">'+data.div+'</d'+'iv>');
|
||||||
checkbox.change(function() {
|
$("#endfitness").html(data.endfitness)
|
||||||
// Check to see if the checkbox is checked.
|
$("#endfatigue").html(data.endfatigue)
|
||||||
// If it is, show the fields and populate the input.
|
$("#endform").html(data.endform)
|
||||||
// If not, hide the fields.
|
console.log('done');
|
||||||
if (checkbox.is(':checked')) {
|
|
||||||
// Show the hidden fields.
|
|
||||||
hidden.show();
|
|
||||||
} else {
|
|
||||||
// Make sure that the hidden fields are indeed
|
|
||||||
// hidden.
|
|
||||||
hidden.hide();
|
|
||||||
|
|
||||||
// You may also want to clear the value of the
|
|
||||||
// hidden fields here. Just in case somebody
|
|
||||||
// shows the fields, enters data to them and then
|
|
||||||
// unticks the checkbox.
|
|
||||||
//
|
|
||||||
// This would do the job:
|
|
||||||
//
|
|
||||||
// $("#hidden_field").val("");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
|
||||||
|
console.log("CSRF token",csrftoken);
|
||||||
|
|
||||||
|
function csrfSafeMethod(method) {
|
||||||
|
// these HTTP methods do not require CSRF protection
|
||||||
|
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
|
||||||
|
}
|
||||||
|
$.ajaxSetup({
|
||||||
|
beforeSend: function(xhr, settings) {
|
||||||
|
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
|
||||||
|
xhr.setRequestHeader("X-CSRFToken", csrftoken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#performanceform").on('change', function(evt) {
|
||||||
|
submit_form();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
|
||||||
<script src="https://cdn.pydata.org/bokeh/release/bokeh-2.2.3.min.js"></script>
|
<script src="https://cdn.pydata.org/bokeh/release/bokeh-2.2.3.min.js"></script>
|
||||||
<script async="true" type="text/javascript">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{ chartscript |safe }}
|
<div id="id_script">
|
||||||
|
{{ chartscript |safe }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Set things up to resize the plot on a window resize. You can play with
|
|
||||||
// the arguments of resize_width_height() to change the plot's behavior.
|
|
||||||
var plot_resize_setup = function () {
|
|
||||||
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
|
|
||||||
var plot = Bokeh.index[plotid];
|
|
||||||
var plotresizer = function() {
|
|
||||||
// arguments: use width, use height, maintain aspect ratio
|
|
||||||
plot.resize_width_height(true, false, false);
|
|
||||||
};
|
|
||||||
window.addEventListener('resize', plotresizer);
|
|
||||||
plotresizer();
|
|
||||||
};
|
|
||||||
window.addEventListener('load', plot_resize_setup);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{% if rower.user %}
|
{% if rower.user %}
|
||||||
<h1>Fitness Progress for {{ rower.user.first_name }} </h1>
|
<h1>Fitness Progress for {{ rower.user.first_name }} </h1>
|
||||||
@@ -77,24 +80,68 @@
|
|||||||
<h1>Fitness Progress for {{ user.first_name }} </h1>
|
<h1>Fitness Progress for {{ user.first_name }} </h1>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<p>
|
|
||||||
Text Explaining Performance Manager
|
|
||||||
</p>
|
|
||||||
|
|
||||||
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<li class="grid_2">
|
<li class="grid_4">
|
||||||
<form enctype="multipart/form-data" action="/rowers/performancemanager/user/{{ rower.user.id }}/" method="post">
|
<div id="id_chart">
|
||||||
|
{{ the_div|safe }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="grid_1">
|
||||||
|
<form id="performanceform" enctype="multipart/form-data" method="post">
|
||||||
<table>
|
<table>
|
||||||
{{ form.as_table }}
|
{{ form.as_table }}
|
||||||
</table>
|
</table>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input name='daterange' class="button green" type="submit" value="Submit">
|
<input name='form' class="button" type="submit" value="Submit">
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_4">
|
<li class="grid_2">
|
||||||
{{ the_div|safe }}
|
<p>
|
||||||
|
The Performance Manager on this page is based on scientific literature
|
||||||
|
on modeling human performance. A good description can be found
|
||||||
|
<a href="https://fellrnr.com/wiki/Modeling_Human_Performance" target="_">here</a>.
|
||||||
|
Every person is different. This statement has implications for training and modeling of
|
||||||
|
training impact. Each person differs in their response to training, diet, rest, or
|
||||||
|
other factors. You are an experiment of one, a unique person and all models are
|
||||||
|
wrong (but some are useful). Be prepared to learn from this chart, to experiment
|
||||||
|
and perhaps to go against established advice.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The chart models your performance over a time period that you can set with the form
|
||||||
|
on the left. The model balances out after a few weeks of regular training, so don't
|
||||||
|
make this chart shorter than a few months.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
For this chart to reflect your fitness and freshness, it is important to have all workouts on
|
||||||
|
Rowsandall.com. You can automatically import workouts from other fitness platforms. Change
|
||||||
|
your <a href="/rowers/me/exportsettings/">Import and Export Settings here.</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The time constants used in generating this performance chart were
|
||||||
|
a fitness decay constant of {{ rower.kfit }} days
|
||||||
|
and a fatigue decay constant of {{ rower.kfatigue }} days.
|
||||||
|
You can change these values in your <a href="/rowers/me/preferences/">Profile Settings</a>.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li class="grid_1">
|
||||||
|
<div class="rounder">
|
||||||
|
<p>
|
||||||
|
<table width="100%">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><h2>Fitness</h2></td><td><h2><span id="endfitness">{{ endfitness }}</span></h2></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><h2>Fatigue</h2></td><td><h2><span id="endfatigue"> {{ endfatigue }}</span></h2></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><h2>Freshness</h2></td><td><h2><span id="endform"> {{ endform }}</span></h2></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@@ -102,6 +149,8 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% block sidebar %}
|
{% block sidebar %}
|
||||||
{% include 'menu_analytics.html' %}
|
{% include 'menu_analytics.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -99,11 +99,14 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
<h2>Range over which Critical Power rolling data (fitness) are calculated</h2>
|
<h2>Fitness and Performance Manager Settings</h2>
|
||||||
<p>Use this form to change the number of weeks over which Rowsandall
|
<p>Use this form to change the parameters affecting your performance management.</p>
|
||||||
keeps track of your Critical Power. </p>
|
<p>A shorter range for the CP calculations
|
||||||
<p>A shorter range will give you notifications of fitness improvements more often,
|
will give you notifications of fitness improvements more often,
|
||||||
but will also quickly forget those breakthrough workouts.</p>
|
but will also quickly forget those breakthrough workouts. Shorter decay
|
||||||
|
time constants for the performance manager will model a quicker building up
|
||||||
|
of fitness and a faster recovery. Recommended values are 42 days (fitness)
|
||||||
|
and 7 days (fatigue).</p>
|
||||||
<table>
|
<table>
|
||||||
{{ cpform.as_table }}
|
{{ cpform.as_table }}
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<input name='form' class='green button' type='submit' value="Submit">
|
<input name='form' class='button' type='submit' value="Submit">
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ class CPChartTest(TestCase):
|
|||||||
'duplicate': False,
|
'duplicate': False,
|
||||||
'avghr': '160',
|
'avghr': '160',
|
||||||
'avgpwr': 0,
|
'avgpwr': 0,
|
||||||
|
'rpe':4,
|
||||||
'avgspm': 40,
|
'avgspm': 40,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-19
@@ -4,6 +4,7 @@ from __future__ import print_function
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
#from __future__ import print_function
|
#from __future__ import print_function
|
||||||
from .statements import *
|
from .statements import *
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
@override_settings(TESTING=True)
|
@override_settings(TESTING=True)
|
||||||
class EmailUpload(TestCase):
|
class EmailUpload(TestCase):
|
||||||
@@ -62,6 +63,7 @@ workout run
|
|||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype': '1x',
|
'boattype': '1x',
|
||||||
'notes': 'aap noot mies',
|
'notes': 'aap noot mies',
|
||||||
|
'rpe':1,
|
||||||
'make_plot': False,
|
'make_plot': False,
|
||||||
'upload_to_C2': False,
|
'upload_to_C2': False,
|
||||||
'plottype': 'timeplot',
|
'plottype': 'timeplot',
|
||||||
@@ -84,27 +86,29 @@ workout run
|
|||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||||
def test_uploadapi2(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
def test_uploadapi2(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||||
form_data = {
|
with transaction.atomic():
|
||||||
'title': 'test',
|
form_data = {
|
||||||
'workouttype':'rower',
|
'title': 'test',
|
||||||
'boattype': '1x',
|
'workouttype':'rower',
|
||||||
'notes': 'aap noot mies',
|
'boattype': '1x',
|
||||||
'make_plot': False,
|
'notes': 'aap noot mies',
|
||||||
'upload_to_C2': False,
|
'make_plot': False,
|
||||||
'plottype': 'timeplot',
|
'upload_to_C2': False,
|
||||||
'file': 'media/mailbox_attachments/colin3.csv',
|
'plottype': 'timeplot',
|
||||||
'secret': settings.UPLOAD_SERVICE_SECRET,
|
'rpe':4,
|
||||||
'useremail': 'sander2@ds.nl',
|
'file': 'media/mailbox_attachments/colin3.csv',
|
||||||
}
|
'secret': settings.UPLOAD_SERVICE_SECRET,
|
||||||
|
'useremail': 'sander2@ds.nl',
|
||||||
|
}
|
||||||
|
|
||||||
url = reverse('workout_upload_api')
|
url = reverse('workout_upload_api')
|
||||||
response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533')
|
response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533')
|
||||||
self.assertEqual(response.status_code,200)
|
self.assertEqual(response.status_code,200)
|
||||||
|
|
||||||
# should also test if workout is created
|
# should also test if workout is created
|
||||||
w = Workout.objects.get(id=1)
|
w = Workout.objects.get(id=1)
|
||||||
self.assertEqual(w.name,'test')
|
self.assertEqual(w.name,'test')
|
||||||
self.assertEqual(w.notes,'aap noot mies')
|
self.assertEqual(w.notes,'aap noot mies')
|
||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class DataTest(TestCase):
|
|||||||
'weightcategory':'lwt',
|
'weightcategory':'lwt',
|
||||||
'adaptiveclass': 'PR1',
|
'adaptiveclass': 'PR1',
|
||||||
'workouttype':'water',
|
'workouttype':'water',
|
||||||
|
'rpe':1,
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'private':False,
|
'private':False,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ class ForceUnits(TestCase):
|
|||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
|
'rpe': 1,
|
||||||
'file': f,
|
'file': f,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,6 +101,7 @@ class ForceUnits(TestCase):
|
|||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
|
'rpe': 1,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
@@ -131,6 +133,7 @@ class ForceUnits(TestCase):
|
|||||||
file_data = {'file': f}
|
file_data = {'file': f}
|
||||||
form_data = {
|
form_data = {
|
||||||
'title':'test',
|
'title':'test',
|
||||||
|
'rpe':1,
|
||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
|||||||
#from __future__ import print_function
|
#from __future__ import print_function
|
||||||
from .statements import *
|
from .statements import *
|
||||||
nu = datetime.datetime.now()
|
nu = datetime.datetime.now()
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
from rowers.views import add_defaultfavorites
|
from rowers.views import add_defaultfavorites
|
||||||
|
|
||||||
@@ -50,7 +51,9 @@ class ViewTest(TestCase):
|
|||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
|
'rpe':4,
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
|
'rpe':6,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
@@ -100,6 +103,7 @@ class ViewTest(TestCase):
|
|||||||
'adaptiveclass':'PR1',
|
'adaptiveclass':'PR1',
|
||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
|
'rpe':4,
|
||||||
'dragfactor':'112',
|
'dragfactor':'112',
|
||||||
'private':True,
|
'private':True,
|
||||||
'notes':'noot mies',
|
'notes':'noot mies',
|
||||||
@@ -141,6 +145,7 @@ class ViewTest(TestCase):
|
|||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
|
'rpe':6,
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_C2':False,
|
'upload_to_C2':False,
|
||||||
'upload_to_Strava':False,
|
'upload_to_Strava':False,
|
||||||
@@ -193,6 +198,7 @@ class ViewTest(TestCase):
|
|||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
|
'rpe':6,
|
||||||
}
|
}
|
||||||
|
|
||||||
form = DocumentsForm(form_data,file_data)
|
form = DocumentsForm(form_data,file_data)
|
||||||
@@ -229,6 +235,7 @@ class ViewTest(TestCase):
|
|||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
|
'rpe':6,
|
||||||
}
|
}
|
||||||
|
|
||||||
form = DocumentsForm(form_data,file_data)
|
form = DocumentsForm(form_data,file_data)
|
||||||
@@ -263,6 +270,7 @@ class ViewTest(TestCase):
|
|||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
|
'rpe':6,
|
||||||
}
|
}
|
||||||
|
|
||||||
form = DocumentsForm(form_data,file_data)
|
form = DocumentsForm(form_data,file_data)
|
||||||
@@ -313,6 +321,7 @@ class ViewTest(TestCase):
|
|||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
|
'rpe':6,
|
||||||
}
|
}
|
||||||
|
|
||||||
form = DocumentsForm(form_data,file_data)
|
form = DocumentsForm(form_data,file_data)
|
||||||
@@ -350,6 +359,7 @@ class ViewTest(TestCase):
|
|||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
|
'rpe':6,
|
||||||
}
|
}
|
||||||
|
|
||||||
form = DocumentsForm(form_data,file_data)
|
form = DocumentsForm(form_data,file_data)
|
||||||
@@ -389,6 +399,7 @@ class ViewTest(TestCase):
|
|||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
|
'rpe':6,
|
||||||
}
|
}
|
||||||
|
|
||||||
form = DocumentsForm(form_data,file_data)
|
form = DocumentsForm(form_data,file_data)
|
||||||
@@ -424,6 +435,7 @@ class ViewTest(TestCase):
|
|||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
|
'rpe':1,
|
||||||
'file': f,
|
'file': f,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +471,7 @@ class ViewTest(TestCase):
|
|||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
|
'rpe':1,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'file': f,
|
||||||
@@ -531,6 +544,7 @@ class ViewTest(TestCase):
|
|||||||
file_data = {'file': f}
|
file_data = {'file': f}
|
||||||
form_data = {
|
form_data = {
|
||||||
'title':'test',
|
'title':'test',
|
||||||
|
'rpe':1,
|
||||||
'workouttype':'water',
|
'workouttype':'water',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
@@ -570,6 +584,7 @@ class ViewTest(TestCase):
|
|||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
|
'rpe':4,
|
||||||
'file': f,
|
'file': f,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,35 +638,37 @@ class ViewTest(TestCase):
|
|||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
def test_upload_view_RP_interval(self, mocked_sqlalchemy):
|
def test_upload_view_RP_interval(self, mocked_sqlalchemy):
|
||||||
self.c.login(username='john',password='koeinsloot')
|
with transaction.atomic():
|
||||||
|
self.c.login(username='john',password='koeinsloot')
|
||||||
|
|
||||||
filename = 'rowers/tests/testdata/RP_interval.csv'
|
filename = 'rowers/tests/testdata/RP_interval.csv'
|
||||||
f = open(filename,'rb')
|
f = open(filename,'rb')
|
||||||
file_data = {'file': f}
|
file_data = {'file': f}
|
||||||
form_data = {
|
form_data = {
|
||||||
'title':'test',
|
'title':'test',
|
||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
'file': f,
|
'rpe':1,
|
||||||
}
|
'file': f,
|
||||||
|
}
|
||||||
|
|
||||||
form = DocumentsForm(form_data,file_data)
|
form = DocumentsForm(form_data,file_data)
|
||||||
|
|
||||||
response = self.c.post('/rowers/workout/upload/', form_data, follow=True)
|
response = self.c.post('/rowers/workout/upload/', form_data, follow=True)
|
||||||
self.assertRedirects(response, expected_url='/rowers/workout/'+encoded1+'/edit/',
|
self.assertRedirects(response, expected_url='/rowers/workout/'+encoded1+'/edit/',
|
||||||
status_code=302,target_status_code=200)
|
status_code=302,target_status_code=200)
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
w = Workout.objects.get(id=1)
|
w = Workout.objects.get(id=1)
|
||||||
f_to_be_deleted = w.csvfilename
|
f_to_be_deleted = w.csvfilename
|
||||||
try:
|
try:
|
||||||
os.remove(f_to_be_deleted+'.gz')
|
os.remove(f_to_be_deleted+'.gz')
|
||||||
except (FileNotFoundError,OSError):
|
except (FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -667,6 +684,7 @@ class ViewTest(TestCase):
|
|||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
|
'rpe':4,
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
@@ -699,6 +717,7 @@ class ViewTest(TestCase):
|
|||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
|
'rpe':4,
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
@@ -731,6 +750,7 @@ class ViewTest(TestCase):
|
|||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
|
'rpe':4,
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
'plottype':'timeplot',
|
'plottype':'timeplot',
|
||||||
@@ -762,6 +782,7 @@ class ViewTest(TestCase):
|
|||||||
'title':'test',
|
'title':'test',
|
||||||
'workouttype':'rower',
|
'workouttype':'rower',
|
||||||
'boattype':'1x',
|
'boattype':'1x',
|
||||||
|
'rpe':4,
|
||||||
'notes':'aap noot mies',
|
'notes':'aap noot mies',
|
||||||
'make_plot':False,
|
'make_plot':False,
|
||||||
'upload_to_c2':False,
|
'upload_to_c2':False,
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ nu = datetime.datetime.now()
|
|||||||
|
|
||||||
|
|
||||||
tested = [
|
tested = [
|
||||||
'/rowers/me/delete/'
|
'/rowers/me/delete/',
|
||||||
|
'/rowers/performancemanager/'
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
#@pytest.mark.django_db
|
#@pytest.mark.django_db
|
||||||
@@ -76,7 +78,7 @@ class URLTests(TestCase):
|
|||||||
'/rowers/agegroupcp/30/1/',
|
'/rowers/agegroupcp/30/1/',
|
||||||
'/rowers/agegrouprecords/male/hwt/',
|
'/rowers/agegrouprecords/male/hwt/',
|
||||||
'/rowers/agegrouprecords/male/hwt/2000m/',
|
'/rowers/agegrouprecords/male/hwt/2000m/',
|
||||||
'/rowers/agegrouprecords/male/hwt/2000min/',
|
'/rowers/agegrouprecords/male/hwt/30min/',
|
||||||
'/rowers/ajax_agegroup/45/hwt/male/1/',
|
'/rowers/ajax_agegroup/45/hwt/male/1/',
|
||||||
'/rowers/analysis/',
|
'/rowers/analysis/',
|
||||||
'/rowers/analysis/user/1/',
|
'/rowers/analysis/user/1/',
|
||||||
@@ -240,6 +242,8 @@ class URLTests(TestCase):
|
|||||||
# '/rowers/workouts-join-select/2016-01-01/2016-12-31/',
|
# '/rowers/workouts-join-select/2016-01-01/2016-12-31/',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# urlstotest = ['/rowers/createplan/user/1/']
|
# urlstotest = ['/rowers/createplan/user/1/']
|
||||||
|
|
||||||
lijst = []
|
lijst = []
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals, absolute_import
|
|||||||
from rowers.views.statements import *
|
from rowers.views.statements import *
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
|
import simplejson
|
||||||
from jinja2 import Template,Environment,FileSystemLoader
|
from jinja2 import Template,Environment,FileSystemLoader
|
||||||
|
|
||||||
def floatformat(x,prec=2):
|
def floatformat(x,prec=2):
|
||||||
@@ -1547,17 +1548,21 @@ def performancemanager_view(request,userid=0,mode='rower',
|
|||||||
startdate=timezone.now()-timezone.timedelta(days=365),
|
startdate=timezone.now()-timezone.timedelta(days=365),
|
||||||
enddate=timezone.now()):
|
enddate=timezone.now()):
|
||||||
|
|
||||||
|
is_ajax = False
|
||||||
|
if request.is_ajax():
|
||||||
|
is_ajax = True
|
||||||
|
|
||||||
therower = getrequestrower(request,userid=userid)
|
therower = getrequestrower(request,userid=userid)
|
||||||
theuser = therower.user
|
theuser = therower.user
|
||||||
|
|
||||||
kfitness = 42
|
kfitness = therower.kfit
|
||||||
kfatigue = 7
|
kfatigue = therower.kfatigue
|
||||||
fitnesstest = 20
|
fitnesstest = 20
|
||||||
metricchoice = 'trimp'
|
metricchoice = 'trimp'
|
||||||
modelchoice = 'tsb'
|
modelchoice = 'tsb'
|
||||||
usefitscore = False
|
usefitscore = False
|
||||||
doform = False
|
doform = therower.showfresh
|
||||||
dofatigue = False
|
dofatigue = therower.showfit
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = PerformanceManagerForm(request.POST)
|
form = PerformanceManagerForm(request.POST)
|
||||||
@@ -1567,10 +1572,13 @@ def performancemanager_view(request,userid=0,mode='rower',
|
|||||||
metricchoice = form.cleaned_data['metricchoice']
|
metricchoice = form.cleaned_data['metricchoice']
|
||||||
dofatigue = form.cleaned_data['dofatigue']
|
dofatigue = form.cleaned_data['dofatigue']
|
||||||
doform = form.cleaned_data['doform']
|
doform = form.cleaned_data['doform']
|
||||||
|
therower.showfresh = doform
|
||||||
|
therower.showfatigue = dofatigue
|
||||||
|
therower.save()
|
||||||
else:
|
else:
|
||||||
form = PerformanceManagerForm()
|
form = PerformanceManagerForm()
|
||||||
|
|
||||||
script, thediv = performance_chart(
|
script, thediv, endfitness, endfatigue, endform = performance_chart(
|
||||||
theuser,startdate=startdate,enddate=enddate,
|
theuser,startdate=startdate,enddate=enddate,
|
||||||
kfitness = kfitness,
|
kfitness = kfitness,
|
||||||
kfatigue = kfatigue,
|
kfatigue = kfatigue,
|
||||||
@@ -1590,6 +1598,17 @@ def performancemanager_view(request,userid=0,mode='rower',
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if is_ajax:
|
||||||
|
response = json.dumps({
|
||||||
|
'script':script,
|
||||||
|
'div':thediv,
|
||||||
|
'endform':int(endform),
|
||||||
|
'endfitness': int(endfitness),
|
||||||
|
'endfatigue': int(endfatigue),
|
||||||
|
})
|
||||||
|
|
||||||
|
return(HttpResponse(response,content_type='application/json'))
|
||||||
|
|
||||||
|
|
||||||
return render(request,'performancemanager.html',
|
return render(request,'performancemanager.html',
|
||||||
{
|
{
|
||||||
@@ -1600,6 +1619,9 @@ def performancemanager_view(request,userid=0,mode='rower',
|
|||||||
'the_div':thediv,
|
'the_div':thediv,
|
||||||
'mode':mode,
|
'mode':mode,
|
||||||
'form':form,
|
'form':form,
|
||||||
|
'endfitness':int(endfitness),
|
||||||
|
'endfatigue':int(endfatigue),
|
||||||
|
'endform':int(endform),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -570,9 +570,13 @@ def rower_prefs_view(request,userid=0,message=""):
|
|||||||
if cpform.is_valid():
|
if cpform.is_valid():
|
||||||
cd = cpform.cleaned_data
|
cd = cpform.cleaned_data
|
||||||
cprange = cd['cprange']
|
cprange = cd['cprange']
|
||||||
|
kfit = cd['kfit']
|
||||||
|
kfatigue = cd['kfatigue']
|
||||||
r.cprange = cprange
|
r.cprange = cprange
|
||||||
|
r.kfit = kfit
|
||||||
|
r.kfatigue = kfatigue
|
||||||
r.save()
|
r.save()
|
||||||
messages.info(request,'Updated CP range value')
|
messages.info(request,'Updated CP range and time decay constants')
|
||||||
success = dataprep.update_rolling_cp(r,mytypes.otwtypes,'water')
|
success = dataprep.update_rolling_cp(r,mytypes.otwtypes,'water')
|
||||||
success = dataprep.update_rolling_cp(r,mytypes.otetypes,'erg')
|
success = dataprep.update_rolling_cp(r,mytypes.otetypes,'erg')
|
||||||
|
|
||||||
|
|||||||
@@ -585,12 +585,19 @@ def addmanual_view(request,raceid=0):
|
|||||||
weightcategory = form.cleaned_data['weightcategory']
|
weightcategory = form.cleaned_data['weightcategory']
|
||||||
adaptiveclass = form.cleaned_data['adaptiveclass']
|
adaptiveclass = form.cleaned_data['adaptiveclass']
|
||||||
distance = form.cleaned_data['distance']
|
distance = form.cleaned_data['distance']
|
||||||
|
try:
|
||||||
|
rpe = form.cleaned_data['rpe']
|
||||||
|
if not rpe:
|
||||||
|
rpe = -1
|
||||||
|
except KeyError:
|
||||||
|
rpe = -1
|
||||||
notes = form.cleaned_data['notes']
|
notes = form.cleaned_data['notes']
|
||||||
thetimezone = form.cleaned_data['timezone']
|
thetimezone = form.cleaned_data['timezone']
|
||||||
private = form.cleaned_data['private']
|
private = form.cleaned_data['private']
|
||||||
avghr = metricsform.cleaned_data['avghr']
|
avghr = metricsform.cleaned_data['avghr']
|
||||||
avgpwr = metricsform.cleaned_data['avgpwr']
|
avgpwr = metricsform.cleaned_data['avgpwr']
|
||||||
avgspm = metricsform.cleaned_data['avgspm']
|
avgspm = metricsform.cleaned_data['avgspm']
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ps = form.cleaned_data['plannedsession']
|
ps = form.cleaned_data['plannedsession']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -632,6 +639,7 @@ def addmanual_view(request,raceid=0):
|
|||||||
id,message = dataprep.create_row_df(r,
|
id,message = dataprep.create_row_df(r,
|
||||||
distance,
|
distance,
|
||||||
duration,startdatetime,
|
duration,startdatetime,
|
||||||
|
rpe=rpe,
|
||||||
weightcategory=weightcategory,
|
weightcategory=weightcategory,
|
||||||
adaptiveclass=adaptiveclass,
|
adaptiveclass=adaptiveclass,
|
||||||
avghr=avghr,
|
avghr=avghr,
|
||||||
@@ -657,6 +665,7 @@ def addmanual_view(request,raceid=0):
|
|||||||
w.notes = notes
|
w.notes = notes
|
||||||
w.plannedsession = ps
|
w.plannedsession = ps
|
||||||
w.name = name
|
w.name = name
|
||||||
|
w.rpe = rpe
|
||||||
w.workouttype = workouttype
|
w.workouttype = workouttype
|
||||||
w.boattype = boattype
|
w.boattype = boattype
|
||||||
w.save()
|
w.save()
|
||||||
@@ -4355,6 +4364,12 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
|||||||
notes = form.cleaned_data['notes']
|
notes = form.cleaned_data['notes']
|
||||||
newdragfactor = form.cleaned_data['dragfactor']
|
newdragfactor = form.cleaned_data['dragfactor']
|
||||||
thetimezone = form.cleaned_data['timezone']
|
thetimezone = form.cleaned_data['timezone']
|
||||||
|
try:
|
||||||
|
rpe = form.cleaned_data['rpe']
|
||||||
|
if not rpe:
|
||||||
|
rpe = -1
|
||||||
|
except KeyError:
|
||||||
|
rpe = -1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ps = form.cleaned_data['plannedsession']
|
ps = form.cleaned_data['plannedsession']
|
||||||
@@ -4421,6 +4436,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
|||||||
row.weightcategory = weightcategory
|
row.weightcategory = weightcategory
|
||||||
row.adaptiveclass = adaptiveclass
|
row.adaptiveclass = adaptiveclass
|
||||||
row.notes = notes
|
row.notes = notes
|
||||||
|
row.rpe = rpe
|
||||||
row.duration = duration
|
row.duration = duration
|
||||||
row.distance = distance
|
row.distance = distance
|
||||||
row.boattype = boattype
|
row.boattype = boattype
|
||||||
@@ -4864,6 +4880,10 @@ def workout_upload_api(request):
|
|||||||
t = form.cleaned_data['title']
|
t = form.cleaned_data['title']
|
||||||
boattype = form.cleaned_data['boattype']
|
boattype = form.cleaned_data['boattype']
|
||||||
workouttype = form.cleaned_data['workouttype']
|
workouttype = form.cleaned_data['workouttype']
|
||||||
|
try:
|
||||||
|
rpe = form.cleaned_data['rpe']
|
||||||
|
except KeyError:
|
||||||
|
rpe = -1
|
||||||
if rowerform.is_valid():
|
if rowerform.is_valid():
|
||||||
u = rowerform.cleaned_data['user']
|
u = rowerform.cleaned_data['user']
|
||||||
r = getrower(u)
|
r = getrower(u)
|
||||||
@@ -4919,6 +4939,7 @@ def workout_upload_api(request):
|
|||||||
boattype=boattype,
|
boattype=boattype,
|
||||||
makeprivate=makeprivate,
|
makeprivate=makeprivate,
|
||||||
title = t,
|
title = t,
|
||||||
|
rpe=rpe,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
uploadoptions=post_data,
|
uploadoptions=post_data,
|
||||||
)
|
)
|
||||||
@@ -5039,6 +5060,13 @@ def workout_upload_view(request,
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
boattype = '1x'
|
boattype = '1x'
|
||||||
|
|
||||||
|
try:
|
||||||
|
rpe = docformoptions['rpe']
|
||||||
|
if not rpe:
|
||||||
|
rpe = -1
|
||||||
|
except KeyError:
|
||||||
|
rpe = -1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
notes = docformoptions['notes']
|
notes = docformoptions['notes']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -5116,6 +5144,10 @@ def workout_upload_view(request,
|
|||||||
t = form.cleaned_data['title']
|
t = form.cleaned_data['title']
|
||||||
workouttype = form.cleaned_data['workouttype']
|
workouttype = form.cleaned_data['workouttype']
|
||||||
boattype = form.cleaned_data['boattype']
|
boattype = form.cleaned_data['boattype']
|
||||||
|
try:
|
||||||
|
rpe = form.cleaned_data['rpe']
|
||||||
|
except KeyError:
|
||||||
|
rpe = -1
|
||||||
|
|
||||||
request.session['docformoptions'] = {
|
request.session['docformoptions'] = {
|
||||||
'workouttype':workouttype,
|
'workouttype':workouttype,
|
||||||
@@ -5156,6 +5188,7 @@ def workout_upload_view(request,
|
|||||||
'upload_to_TrainingPeaks':upload_to_tp,
|
'upload_to_TrainingPeaks':upload_to_tp,
|
||||||
'landingpage':landingpage,
|
'landingpage':landingpage,
|
||||||
'boattype': boattype,
|
'boattype': boattype,
|
||||||
|
'rpe':rpe,
|
||||||
'workouttype': workouttype,
|
'workouttype': workouttype,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5171,6 +5204,7 @@ def workout_upload_view(request,
|
|||||||
workouttype=workouttype,
|
workouttype=workouttype,
|
||||||
workoutsource=workoutsource,
|
workoutsource=workoutsource,
|
||||||
boattype=boattype,
|
boattype=boattype,
|
||||||
|
rpe=rpe,
|
||||||
makeprivate=makeprivate,
|
makeprivate=makeprivate,
|
||||||
title = t,
|
title = t,
|
||||||
notes=notes,
|
notes=notes,
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Reference in New Issue
Block a user