Merge branch 'release/v14.72'
This commit is contained in:
@@ -1242,7 +1242,7 @@ def fetchcp(rower,theworkouts,table='cpdata'):
|
||||
def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
|
||||
avghr=None,avgpwr=None,avgspm=None,
|
||||
rankingpiece = False,
|
||||
duplicate=False,
|
||||
duplicate=False,rpe=-1,
|
||||
title='Manual entry',notes='',weightcategory='hwt',
|
||||
adaptiveclass='None'):
|
||||
|
||||
@@ -1351,6 +1351,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
workoutsource='unknown',
|
||||
notes='', totaldist=0, totaltime=0,
|
||||
rankingpiece=False,
|
||||
rpe=-1,
|
||||
duplicate=False,
|
||||
summary='',
|
||||
makeprivate=False,
|
||||
@@ -1583,6 +1584,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
workoutsource=workoutsource,
|
||||
rankingpiece=rankingpiece,
|
||||
forceunit=forceunit,
|
||||
rpe=rpe,
|
||||
csvfilename=f2, notes=notes, summary=summary,
|
||||
maxhr=maxhr, averagehr=averagehr,
|
||||
startdatetime=workoutstartdatetime,
|
||||
@@ -1810,6 +1812,7 @@ def new_workout_from_file(r, f2,
|
||||
workoutsource=None,
|
||||
title='Workout',
|
||||
boattype='1x',
|
||||
rpe=-1,
|
||||
makeprivate=False,
|
||||
notes='',
|
||||
uploadoptions={'boattype':'1x','workouttype':'rower'}):
|
||||
@@ -1944,6 +1947,7 @@ def new_workout_from_file(r, f2,
|
||||
dosummary=dosummary,
|
||||
workoutsource=workoutsource,
|
||||
summary=summary,
|
||||
rpe=rpe,
|
||||
inboard=inboard, oarlength=oarlength,
|
||||
title=title,
|
||||
forceunit='N',
|
||||
|
||||
@@ -13,6 +13,20 @@ from rowers.mytypes import otwtypes,otetypes,rowtypes
|
||||
#p0 = [500,350,10,8000]
|
||||
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'):
|
||||
if workouttype in otwtypes:
|
||||
p0 = r.p0
|
||||
|
||||
@@ -245,17 +245,23 @@ class StandardsForm(forms.Form):
|
||||
|
||||
# The form used for uploading files
|
||||
class DocumentsForm(forms.Form):
|
||||
rpechoices = Workout.rpechoices
|
||||
rpechoices = tuple([(-1,'---')]+list(rpechoices))
|
||||
title = forms.CharField(required=False)
|
||||
file = forms.FileField(required=False,
|
||||
validators=[validate_file_extension])
|
||||
|
||||
workouttype = forms.ChoiceField(required=True,
|
||||
choices=Workout.workouttypes)
|
||||
choices=Workout.workouttypes,
|
||||
label='Workout Type')
|
||||
|
||||
boattype = forms.ChoiceField(required=True,
|
||||
choices=mytypes.boattypes,
|
||||
label = "Boat Type")
|
||||
|
||||
rpe = forms.ChoiceField(required=False,
|
||||
choices=rpechoices,
|
||||
label='Rate of Perceived Exertion',initial=-1)
|
||||
|
||||
notes = forms.CharField(required=False,
|
||||
widget=forms.Textarea)
|
||||
|
||||
@@ -97,7 +97,7 @@ import rowers.c2stuff as c2stuff
|
||||
from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima,get_yaxminima,get_yaxmaxima
|
||||
|
||||
from rowers.utils import lbstoN
|
||||
from rowers.datautils import p0
|
||||
from rowers.datautils import p0,rpetotss
|
||||
import rowers.datautils as datautils
|
||||
|
||||
from pandas.core.groupby.groupby import DataError
|
||||
@@ -1650,18 +1650,30 @@ def getfatigues(
|
||||
if metricchoice == 'rscore':
|
||||
factor = 2.0
|
||||
|
||||
for i in range(nrdays):
|
||||
for i in range(nrdays+1):
|
||||
date = startdate+datetime.timedelta(days=i)
|
||||
ws = Workout.objects.filter(user=user.rower,date=date,duplicate=False)
|
||||
weight = 0
|
||||
for w in ws:
|
||||
weight += factor*getattr(w,metricchoice)
|
||||
if getattr(w,metricchoice) == 0:
|
||||
if metricchoice == 'rscore' and w.hrtss != 0:
|
||||
if getattr(w,metricchoice) > 0:
|
||||
weight += factor*getattr(w,metricchoice)
|
||||
if getattr(w,metricchoice) <= 0:
|
||||
if metricchoice == 'rscore' and w.hrtss > 0:
|
||||
weight+= factor*w.hrtss
|
||||
else:
|
||||
elif metricchoice == 'rscore' and w.hrtss <= 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 += 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)
|
||||
|
||||
@@ -1680,6 +1692,7 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
||||
metricchoice='trimp',doform=False,dofatigue=False):
|
||||
|
||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||
TOOLS2 = 'box_zoom,hover'
|
||||
|
||||
|
||||
fatigues = []
|
||||
@@ -1713,7 +1726,9 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
||||
'impulse':impulses,
|
||||
})
|
||||
|
||||
|
||||
endfitness = fitnesses[-1]
|
||||
endfatigue = fatigues[-1]
|
||||
endform = endfitness-endfatigue
|
||||
|
||||
if modelchoice == 'banister':
|
||||
df['fatigue'] = k2*df['fatigue']
|
||||
@@ -1777,18 +1792,18 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
||||
fitlabel = 'PTE (fitness)'
|
||||
fatiguelabel = 'NTE (fatigue)'
|
||||
formlabel = 'Performance'
|
||||
rightaxlabel = 'NTE'
|
||||
if doform:
|
||||
yaxlabel = 'PTE/Performance'
|
||||
rightaxlabel = 'Performance'
|
||||
if dofatigue:
|
||||
yaxlabel = 'PTE/NTE'
|
||||
else:
|
||||
yaxlabel = 'PTE'
|
||||
else:
|
||||
fitlabel = 'Fitness'
|
||||
fatiguelabel = 'Fatigue'
|
||||
formlabel = 'Freshness'
|
||||
rightaxlabel = 'Fatigue'
|
||||
if doform:
|
||||
yaxlabel = 'Fitness/Freshness'
|
||||
rightaxlabel = 'Freshness'
|
||||
if dofatigue:
|
||||
yaxlabel = 'Fitness/Fatigue'
|
||||
else:
|
||||
yaxlabel = 'Fitness'
|
||||
|
||||
@@ -1829,13 +1844,6 @@ def performance_chart(user,startdate=None,enddate=None,kfitness=42,kfatigue=7,
|
||||
|
||||
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.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))
|
||||
|
||||
linked_crosshair = CrosshairTool(dimensions='height')
|
||||
|
||||
hover.tooltips = OrderedDict([
|
||||
#(legend_label,'@testpower'),
|
||||
('Date','@fdate'),
|
||||
(fitlabel,'@fitness'),
|
||||
(fatiguelabel,'@fatigue'),
|
||||
(formlabel,'@form')
|
||||
(fitlabel,'@fitness{int}'),
|
||||
(fatiguelabel,'@fatigue{int}'),
|
||||
(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,
|
||||
toolbar_location=None,
|
||||
toolbar_sticky=False)
|
||||
|
||||
|
||||
|
||||
plot2.x_range = xrange
|
||||
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.xaxis.axis_label = 'Date'
|
||||
|
||||
plot.add_tools(linked_crosshair)
|
||||
plot2.add_tools(linked_crosshair)
|
||||
|
||||
layout = layoutcolumn([plot,plot2])
|
||||
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,
|
||||
|
||||
@@ -881,11 +881,17 @@ class Rower(models.Model):
|
||||
ep3 = models.FloatField(default=1.0,verbose_name="erg CP p4")
|
||||
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)
|
||||
|
||||
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_ut1 = models.IntegerField(default=171,verbose_name="UT1 Power")
|
||||
pw_at = models.IntegerField(default=203,verbose_name="AT Power")
|
||||
@@ -2898,6 +2904,19 @@ class Workout(models.Model):
|
||||
privacychoices = mytypes.privacychoices
|
||||
adaptivetypes = mytypes.adaptivetypes
|
||||
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)
|
||||
team = models.ManyToManyField(Team,blank=True)
|
||||
@@ -2925,12 +2944,18 @@ class Workout(models.Model):
|
||||
distance = models.IntegerField(default=0,blank=True)
|
||||
duration = models.TimeField(blank=True)
|
||||
dragfactor = models.IntegerField(default=0,blank=True)
|
||||
|
||||
# scores
|
||||
trimp = models.IntegerField(default=-1,blank=True)
|
||||
rscore = models.IntegerField(default=-1,blank=True)
|
||||
hrtss = models.IntegerField(default=-1,blank=True)
|
||||
normp = models.IntegerField(default=-1,blank=True)
|
||||
normv = 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(
|
||||
default="hwt",
|
||||
max_length=10,
|
||||
@@ -2958,7 +2983,6 @@ class Workout(models.Model):
|
||||
inboard = models.FloatField(default=0.88)
|
||||
oarlength = models.FloatField(default=2.89)
|
||||
|
||||
|
||||
notes = models.CharField(blank=True,null=True,max_length=1000)
|
||||
summary = models.TextField(blank=True)
|
||||
privacy = models.CharField(default='visible',max_length=30,
|
||||
@@ -3541,6 +3565,7 @@ class WorkoutForm(ModelForm):
|
||||
'dragfactor',
|
||||
'weightcategory',
|
||||
'adaptiveclass',
|
||||
'rpe',
|
||||
'notes',
|
||||
'rankingpiece',
|
||||
'duplicate',
|
||||
@@ -3618,7 +3643,7 @@ class RowerPowerForm(ModelForm):
|
||||
class RowerCPForm(ModelForm):
|
||||
class Meta:
|
||||
model = Rower
|
||||
fields = ['cprange']
|
||||
fields = ['cprange','kfit','kfatigue']
|
||||
|
||||
# Form to set rower's Power zones, including test routines
|
||||
# to enable consistency
|
||||
|
||||
@@ -11,20 +11,29 @@
|
||||
|
||||
|
||||
<ul class="main-content">
|
||||
<!--
|
||||
<li class="rounder">
|
||||
<h2>Performance Manager</h2>
|
||||
<a href="/rowers/performancemanager/">
|
||||
<div class="vignet">
|
||||
<img src="/static/img/perfmanager.png"
|
||||
<img src="/static/img/PM.jpg"
|
||||
alt="Performance Manager">
|
||||
</div>
|
||||
</a>
|
||||
<p>
|
||||
Manager Fitness, Fatigue and Freshness
|
||||
Manage Fitness, Fatigue and Freshness
|
||||
</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 class="rounder">
|
||||
<h2>Compare Workouts</h2>
|
||||
{% if team %}
|
||||
@@ -53,17 +62,6 @@
|
||||
Plot all strokes in a date range and analyze several parameters (Power, Pace, SPM, Heart Rate).
|
||||
</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 class="rounder">
|
||||
<h2>Statistics</h2>
|
||||
<a href="/rowers/user-analysis-select/stats/">
|
||||
@@ -98,17 +96,6 @@
|
||||
<p>
|
||||
Select workouts and make X-Y charts of averages over various metrics
|
||||
</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 class="rounder">
|
||||
<h2>Power Progress</h2>
|
||||
@@ -144,6 +131,17 @@
|
||||
<p>
|
||||
Analyze your Concept2 ranking pieces over a date range and predict your pace on other pieces.
|
||||
</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>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -26,6 +26,16 @@
|
||||
<i class="fas fa-watch-fitness fa-fw"></i> Fitness
|
||||
</label>
|
||||
<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">
|
||||
{% if team %}
|
||||
<a href="/rowers/user-analysis-select/compare/team/{{ team.id }}/">
|
||||
@@ -41,11 +51,6 @@
|
||||
<a href="/rowers/fitness-progress/">
|
||||
<i class="far fa-watch-fitness fa-fw"></i> Power Progress
|
||||
</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="fitness-ranking">
|
||||
<a href="/rowers/ote-bests2/">
|
||||
|
||||
@@ -308,6 +308,11 @@
|
||||
<i class="fas fa-calculator-alt fa-fw"></i> OTW Power
|
||||
</a>
|
||||
</li>
|
||||
<li id="advanced-otwpower">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/zeropower-confirm/">
|
||||
<i class="fas fa-eraser fa-fw"></i> Remove Power Data
|
||||
</a>
|
||||
</li>
|
||||
{% if 'speedcoach2' in workout.workoutsource %}
|
||||
<li id="advanced-usegps">
|
||||
<a href="/rowers/workout/{{ workout.id|encode }}/otwusegps/">
|
||||
|
||||
@@ -4,72 +4,75 @@
|
||||
|
||||
{% block title %}Rowsandall Fitness Progress {% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
{% block scripts %}
|
||||
<script type='text/javascript'
|
||||
src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'>
|
||||
</script>
|
||||
<script>
|
||||
$(function() {
|
||||
|
||||
// Get the form fields and hidden div
|
||||
var checkbox = $("#id_water");
|
||||
var hidden = $("#id_waterboattype");
|
||||
function submit_form() {
|
||||
console.log("form changed");
|
||||
var frm = $("#performanceform");
|
||||
|
||||
var data = new FormData(frm[0]);
|
||||
|
||||
// Hide the fields.
|
||||
// Use JS to do this in case the user doesn't have JS
|
||||
// enabled.
|
||||
$.ajax({
|
||||
url:"/rowers/performancemanager/user/{{ rower.user.id }}/",
|
||||
type: "POST",
|
||||
contentType: false,
|
||||
processData: false,
|
||||
data: data,
|
||||
dataType: 'json',
|
||||
|
||||
hidden.hide();
|
||||
|
||||
|
||||
// Setup an event listener for when the state of the
|
||||
// checkbox changes.
|
||||
checkbox.change(function() {
|
||||
// Check to see if the checkbox is checked.
|
||||
// If it is, show the fields and populate the input.
|
||||
// If not, hide the fields.
|
||||
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("");
|
||||
success: function(data) {
|
||||
console.log(data);
|
||||
// var parsedJSON = $.parseJSON(data); //
|
||||
$("#id_script").replaceWith('<div id="id_script">'+data.script+'</d'+'iv>');
|
||||
$("#id_chart").replaceWith('<div id="id_chart">'+data.div+'</d'+'iv>');
|
||||
$("#endfitness").html(data.endfitness)
|
||||
$("#endfatigue").html(data.endfatigue)
|
||||
$("#endform").html(data.endform)
|
||||
console.log('done');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$(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 async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</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 %}
|
||||
<h1>Fitness Progress for {{ rower.user.first_name }} </h1>
|
||||
@@ -77,24 +80,68 @@
|
||||
<h1>Fitness Progress for {{ user.first_name }} </h1>
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
Text Explaining Performance Manager
|
||||
</p>
|
||||
|
||||
|
||||
<ul class="main-content">
|
||||
<li class="grid_2">
|
||||
<form enctype="multipart/form-data" action="/rowers/performancemanager/user/{{ rower.user.id }}/" method="post">
|
||||
<li class="grid_4">
|
||||
<div id="id_chart">
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
</li>
|
||||
<li class="grid_1">
|
||||
<form id="performanceform" enctype="multipart/form-data" method="post">
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input name='daterange' class="button green" type="submit" value="Submit">
|
||||
<input name='form' class="button" type="submit" value="Submit">
|
||||
</form>
|
||||
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
{{ the_div|safe }}
|
||||
<li class="grid_2">
|
||||
<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>
|
||||
</ul>
|
||||
|
||||
@@ -102,6 +149,8 @@
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'menu_analytics.html' %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -99,11 +99,14 @@
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<form enctype="multipart/form-data" action="" method="post">
|
||||
<h2>Range over which Critical Power rolling data (fitness) are calculated</h2>
|
||||
<p>Use this form to change the number of weeks over which Rowsandall
|
||||
keeps track of your Critical Power. </p>
|
||||
<p>A shorter range will give you notifications of fitness improvements more often,
|
||||
but will also quickly forget those breakthrough workouts.</p>
|
||||
<h2>Fitness and Performance Manager Settings</h2>
|
||||
<p>Use this form to change the parameters affecting your performance management.</p>
|
||||
<p>A shorter range for the CP calculations
|
||||
will give you notifications of fitness improvements more often,
|
||||
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>
|
||||
{{ cpform.as_table }}
|
||||
</table>
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
{% csrf_token %}
|
||||
</p>
|
||||
<p>
|
||||
<input name='form' class='green button' type='submit' value="Submit">
|
||||
<input name='form' class='button' type='submit' value="Submit">
|
||||
</form>
|
||||
</p>
|
||||
</li>
|
||||
|
||||
41
rowers/templates/workout_remove_power_confirm.html
Normal file
41
rowers/templates/workout_remove_power_confirm.html
Normal file
@@ -0,0 +1,41 @@
|
||||
{% extends "newbase.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}Change Workout {% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<h1>Delete Power?</h1>
|
||||
<ul class="main-content">
|
||||
<li class="grid_2">
|
||||
<p>
|
||||
This will delete the power data for the following workout:
|
||||
</p>
|
||||
<table width=100%>
|
||||
<tr>
|
||||
<th>Name:</th><td>{{ workout.name }}</td>
|
||||
</tr><tr>
|
||||
<th>Date:</th><td>{{ workout.date }}</td>
|
||||
</tr><tr>
|
||||
<th>Time:</th><td>{{ workout.starttime }}</td>
|
||||
</tr><tr>
|
||||
<th>Distance:</th><td>{{ workout.distance }}m</td>
|
||||
</tr><tr>
|
||||
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<form action="/rowers/workout/{{ workout.id|encode }}/zeropower/" method="get">
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="Confirm">
|
||||
</form>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include 'menu_workout.html' %}
|
||||
{% endblock %}
|
||||
@@ -195,6 +195,7 @@ class CPChartTest(TestCase):
|
||||
'duplicate': False,
|
||||
'avghr': '160',
|
||||
'avgpwr': 0,
|
||||
'rpe':4,
|
||||
'avgspm': 40,
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
#from __future__ import print_function
|
||||
from .statements import *
|
||||
from django.db import transaction
|
||||
|
||||
@override_settings(TESTING=True)
|
||||
class EmailUpload(TestCase):
|
||||
@@ -62,6 +63,7 @@ workout run
|
||||
'workouttype':'rower',
|
||||
'boattype': '1x',
|
||||
'notes': 'aap noot mies',
|
||||
'rpe':1,
|
||||
'make_plot': False,
|
||||
'upload_to_C2': False,
|
||||
'plottype': 'timeplot',
|
||||
@@ -84,27 +86,29 @@ workout run
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
def test_uploadapi2(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||
form_data = {
|
||||
'title': 'test',
|
||||
'workouttype':'rower',
|
||||
'boattype': '1x',
|
||||
'notes': 'aap noot mies',
|
||||
'make_plot': False,
|
||||
'upload_to_C2': False,
|
||||
'plottype': 'timeplot',
|
||||
'file': 'media/mailbox_attachments/colin3.csv',
|
||||
'secret': settings.UPLOAD_SERVICE_SECRET,
|
||||
'useremail': 'sander2@ds.nl',
|
||||
}
|
||||
with transaction.atomic():
|
||||
form_data = {
|
||||
'title': 'test',
|
||||
'workouttype':'rower',
|
||||
'boattype': '1x',
|
||||
'notes': 'aap noot mies',
|
||||
'make_plot': False,
|
||||
'upload_to_C2': False,
|
||||
'plottype': 'timeplot',
|
||||
'rpe':4,
|
||||
'file': 'media/mailbox_attachments/colin3.csv',
|
||||
'secret': settings.UPLOAD_SERVICE_SECRET,
|
||||
'useremail': 'sander2@ds.nl',
|
||||
}
|
||||
|
||||
url = reverse('workout_upload_api')
|
||||
response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533')
|
||||
self.assertEqual(response.status_code,200)
|
||||
url = reverse('workout_upload_api')
|
||||
response = self.c.post(url,form_data,HTTP_HOST='127.0.0.1:4533')
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
# should also test if workout is created
|
||||
w = Workout.objects.get(id=1)
|
||||
self.assertEqual(w.name,'test')
|
||||
self.assertEqual(w.notes,'aap noot mies')
|
||||
# should also test if workout is created
|
||||
w = Workout.objects.get(id=1)
|
||||
self.assertEqual(w.name,'test')
|
||||
self.assertEqual(w.notes,'aap noot mies')
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||
|
||||
@@ -32,6 +32,7 @@ class DataTest(TestCase):
|
||||
'weightcategory':'lwt',
|
||||
'adaptiveclass': 'PR1',
|
||||
'workouttype':'water',
|
||||
'rpe':1,
|
||||
'boattype':'1x',
|
||||
'private':False,
|
||||
}
|
||||
|
||||
@@ -55,6 +55,7 @@ class ForceUnits(TestCase):
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'rpe': 1,
|
||||
'file': f,
|
||||
}
|
||||
|
||||
@@ -100,6 +101,7 @@ class ForceUnits(TestCase):
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'make_plot':False,
|
||||
'rpe': 1,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
@@ -131,6 +133,7 @@ class ForceUnits(TestCase):
|
||||
file_data = {'file': f}
|
||||
form_data = {
|
||||
'title':'test',
|
||||
'rpe':1,
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
|
||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
|
||||
#from __future__ import print_function
|
||||
from .statements import *
|
||||
nu = datetime.datetime.now()
|
||||
from django.db import transaction
|
||||
|
||||
from rowers.views import add_defaultfavorites
|
||||
|
||||
@@ -50,7 +51,9 @@ class ViewTest(TestCase):
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'rpe':4,
|
||||
'make_plot':False,
|
||||
'rpe':6,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
@@ -100,6 +103,7 @@ class ViewTest(TestCase):
|
||||
'adaptiveclass':'PR1',
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'rpe':4,
|
||||
'dragfactor':'112',
|
||||
'private':True,
|
||||
'notes':'noot mies',
|
||||
@@ -141,6 +145,7 @@ class ViewTest(TestCase):
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'rpe':6,
|
||||
'make_plot':False,
|
||||
'upload_to_C2':False,
|
||||
'upload_to_Strava':False,
|
||||
@@ -193,6 +198,7 @@ class ViewTest(TestCase):
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
'rpe':6,
|
||||
}
|
||||
|
||||
form = DocumentsForm(form_data,file_data)
|
||||
@@ -229,6 +235,7 @@ class ViewTest(TestCase):
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
'rpe':6,
|
||||
}
|
||||
|
||||
form = DocumentsForm(form_data,file_data)
|
||||
@@ -263,6 +270,7 @@ class ViewTest(TestCase):
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
'rpe':6,
|
||||
}
|
||||
|
||||
form = DocumentsForm(form_data,file_data)
|
||||
@@ -313,6 +321,7 @@ class ViewTest(TestCase):
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
'rpe':6,
|
||||
}
|
||||
|
||||
form = DocumentsForm(form_data,file_data)
|
||||
@@ -350,6 +359,7 @@ class ViewTest(TestCase):
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
'rpe':6,
|
||||
}
|
||||
|
||||
form = DocumentsForm(form_data,file_data)
|
||||
@@ -389,6 +399,7 @@ class ViewTest(TestCase):
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
'rpe':6,
|
||||
}
|
||||
|
||||
form = DocumentsForm(form_data,file_data)
|
||||
@@ -424,6 +435,7 @@ class ViewTest(TestCase):
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'rpe':1,
|
||||
'file': f,
|
||||
}
|
||||
|
||||
@@ -459,6 +471,7 @@ class ViewTest(TestCase):
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'make_plot':False,
|
||||
'rpe':1,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
@@ -531,6 +544,7 @@ class ViewTest(TestCase):
|
||||
file_data = {'file': f}
|
||||
form_data = {
|
||||
'title':'test',
|
||||
'rpe':1,
|
||||
'workouttype':'water',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
@@ -570,6 +584,7 @@ class ViewTest(TestCase):
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'rpe':4,
|
||||
'file': f,
|
||||
}
|
||||
|
||||
@@ -623,35 +638,37 @@ class ViewTest(TestCase):
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
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'
|
||||
f = open(filename,'rb')
|
||||
file_data = {'file': f}
|
||||
form_data = {
|
||||
'title':'test',
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'file': f,
|
||||
}
|
||||
filename = 'rowers/tests/testdata/RP_interval.csv'
|
||||
f = open(filename,'rb')
|
||||
file_data = {'file': f}
|
||||
form_data = {
|
||||
'title':'test',
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
'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)
|
||||
self.assertRedirects(response, expected_url='/rowers/workout/'+encoded1+'/edit/',
|
||||
response = self.c.post('/rowers/workout/upload/', form_data, follow=True)
|
||||
self.assertRedirects(response, expected_url='/rowers/workout/'+encoded1+'/edit/',
|
||||
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)
|
||||
f_to_be_deleted = w.csvfilename
|
||||
try:
|
||||
os.remove(f_to_be_deleted+'.gz')
|
||||
except (FileNotFoundError,OSError):
|
||||
pass
|
||||
w = Workout.objects.get(id=1)
|
||||
f_to_be_deleted = w.csvfilename
|
||||
try:
|
||||
os.remove(f_to_be_deleted+'.gz')
|
||||
except (FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@@ -667,6 +684,7 @@ class ViewTest(TestCase):
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'rpe':4,
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
@@ -699,6 +717,7 @@ class ViewTest(TestCase):
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'rpe':4,
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
@@ -731,6 +750,7 @@ class ViewTest(TestCase):
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'notes':'aap noot mies',
|
||||
'rpe':4,
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
'plottype':'timeplot',
|
||||
@@ -762,6 +782,7 @@ class ViewTest(TestCase):
|
||||
'title':'test',
|
||||
'workouttype':'rower',
|
||||
'boattype':'1x',
|
||||
'rpe':4,
|
||||
'notes':'aap noot mies',
|
||||
'make_plot':False,
|
||||
'upload_to_c2':False,
|
||||
|
||||
@@ -10,7 +10,9 @@ nu = datetime.datetime.now()
|
||||
|
||||
|
||||
tested = [
|
||||
'/rowers/me/delete/'
|
||||
'/rowers/me/delete/',
|
||||
'/rowers/performancemanager/'
|
||||
|
||||
]
|
||||
|
||||
#@pytest.mark.django_db
|
||||
@@ -76,7 +78,7 @@ class URLTests(TestCase):
|
||||
'/rowers/agegroupcp/30/1/',
|
||||
'/rowers/agegrouprecords/male/hwt/',
|
||||
'/rowers/agegrouprecords/male/hwt/2000m/',
|
||||
'/rowers/agegrouprecords/male/hwt/2000min/',
|
||||
'/rowers/agegrouprecords/male/hwt/30min/',
|
||||
'/rowers/ajax_agegroup/45/hwt/male/1/',
|
||||
'/rowers/analysis/',
|
||||
'/rowers/analysis/user/1/',
|
||||
@@ -240,6 +242,8 @@ class URLTests(TestCase):
|
||||
# '/rowers/workouts-join-select/2016-01-01/2016-12-31/',
|
||||
]
|
||||
|
||||
|
||||
|
||||
# urlstotest = ['/rowers/createplan/user/1/']
|
||||
|
||||
lijst = []
|
||||
|
||||
@@ -437,6 +437,8 @@ urlpatterns = [
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/stats/$',views.workout_stats_view,name='workout_stats_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/data/$',views.workout_data_view,
|
||||
name='workout_data_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/zeropower-confirm/$',views.remove_power_confirm_view,
|
||||
name='remove_power_confirm_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/zeropower/$',views.remove_power_view,
|
||||
name='remove_power_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/otwsetpower/$',views.workout_otwsetpower_view,name='workout_otwsetpower_view'),
|
||||
|
||||
@@ -6,6 +6,7 @@ from __future__ import unicode_literals, absolute_import
|
||||
from rowers.views.statements import *
|
||||
|
||||
import collections
|
||||
import simplejson
|
||||
from jinja2 import Template,Environment,FileSystemLoader
|
||||
|
||||
def floatformat(x,prec=2):
|
||||
@@ -1547,17 +1548,21 @@ def performancemanager_view(request,userid=0,mode='rower',
|
||||
startdate=timezone.now()-timezone.timedelta(days=365),
|
||||
enddate=timezone.now()):
|
||||
|
||||
is_ajax = False
|
||||
if request.is_ajax():
|
||||
is_ajax = True
|
||||
|
||||
therower = getrequestrower(request,userid=userid)
|
||||
theuser = therower.user
|
||||
|
||||
kfitness = 42
|
||||
kfatigue = 7
|
||||
kfitness = therower.kfit
|
||||
kfatigue = therower.kfatigue
|
||||
fitnesstest = 20
|
||||
metricchoice = 'trimp'
|
||||
modelchoice = 'tsb'
|
||||
usefitscore = False
|
||||
doform = False
|
||||
dofatigue = False
|
||||
doform = therower.showfresh
|
||||
dofatigue = therower.showfit
|
||||
|
||||
if request.method == 'POST':
|
||||
form = PerformanceManagerForm(request.POST)
|
||||
@@ -1567,10 +1572,13 @@ def performancemanager_view(request,userid=0,mode='rower',
|
||||
metricchoice = form.cleaned_data['metricchoice']
|
||||
dofatigue = form.cleaned_data['dofatigue']
|
||||
doform = form.cleaned_data['doform']
|
||||
therower.showfresh = doform
|
||||
therower.showfatigue = dofatigue
|
||||
therower.save()
|
||||
else:
|
||||
form = PerformanceManagerForm()
|
||||
|
||||
script, thediv = performance_chart(
|
||||
script, thediv, endfitness, endfatigue, endform = performance_chart(
|
||||
theuser,startdate=startdate,enddate=enddate,
|
||||
kfitness = kfitness,
|
||||
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',
|
||||
{
|
||||
@@ -1600,6 +1619,9 @@ def performancemanager_view(request,userid=0,mode='rower',
|
||||
'the_div':thediv,
|
||||
'mode':mode,
|
||||
'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():
|
||||
cd = cpform.cleaned_data
|
||||
cprange = cd['cprange']
|
||||
kfit = cd['kfit']
|
||||
kfatigue = cd['kfatigue']
|
||||
r.cprange = cprange
|
||||
r.kfit = kfit
|
||||
r.kfatigue = kfatigue
|
||||
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.otetypes,'erg')
|
||||
|
||||
|
||||
@@ -585,12 +585,19 @@ def addmanual_view(request,raceid=0):
|
||||
weightcategory = form.cleaned_data['weightcategory']
|
||||
adaptiveclass = form.cleaned_data['adaptiveclass']
|
||||
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']
|
||||
thetimezone = form.cleaned_data['timezone']
|
||||
private = form.cleaned_data['private']
|
||||
avghr = metricsform.cleaned_data['avghr']
|
||||
avgpwr = metricsform.cleaned_data['avgpwr']
|
||||
avgspm = metricsform.cleaned_data['avgspm']
|
||||
|
||||
try:
|
||||
ps = form.cleaned_data['plannedsession']
|
||||
except KeyError:
|
||||
@@ -632,6 +639,7 @@ def addmanual_view(request,raceid=0):
|
||||
id,message = dataprep.create_row_df(r,
|
||||
distance,
|
||||
duration,startdatetime,
|
||||
rpe=rpe,
|
||||
weightcategory=weightcategory,
|
||||
adaptiveclass=adaptiveclass,
|
||||
avghr=avghr,
|
||||
@@ -657,6 +665,7 @@ def addmanual_view(request,raceid=0):
|
||||
w.notes = notes
|
||||
w.plannedsession = ps
|
||||
w.name = name
|
||||
w.rpe = rpe
|
||||
w.workouttype = workouttype
|
||||
w.boattype = boattype
|
||||
w.save()
|
||||
@@ -1274,6 +1283,36 @@ def workouts_join_select(request,
|
||||
'teams':get_my_teams(request.user),
|
||||
})
|
||||
|
||||
@login_required()
|
||||
def remove_power_confirm_view(request,id=0):
|
||||
r = getrower(request.user)
|
||||
workout = get_workout_by_opaqueid(request,id)
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url':'/rowers/list-workouts/',
|
||||
'name':'Workouts'
|
||||
},
|
||||
{
|
||||
'url':get_workout_default_page(request,encoder.encode_hex(workout.id)),
|
||||
'name': encoder.encode_hex(workout.id)
|
||||
},
|
||||
{ 'url':reverse('remove_power_confirm_view',
|
||||
kwargs={'id':encoder.encode_hex(workout.id)}),
|
||||
'name': 'Delete'
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
return render(request,
|
||||
'workout_remove_power_confirm.html',
|
||||
{
|
||||
'workout':workout,
|
||||
'rower':r,
|
||||
'breadcrumbs':breadcrumbs,
|
||||
})
|
||||
|
||||
|
||||
@login_required()
|
||||
def remove_power_view(request,id=0):
|
||||
r = getrower(request.user)
|
||||
@@ -1299,6 +1338,11 @@ def remove_power_view(request,id=0):
|
||||
res = dataprep.dataprep(row.df, id=workout.id)
|
||||
cpdf,delta,cpvalues = dataprep.setcp(workout)
|
||||
|
||||
workout.normp = 0
|
||||
workout.rscore = 0
|
||||
workout.save()
|
||||
|
||||
|
||||
dataprep.initiate_cp(r)
|
||||
|
||||
|
||||
@@ -4320,6 +4364,12 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
||||
notes = form.cleaned_data['notes']
|
||||
newdragfactor = form.cleaned_data['dragfactor']
|
||||
thetimezone = form.cleaned_data['timezone']
|
||||
try:
|
||||
rpe = form.cleaned_data['rpe']
|
||||
if not rpe:
|
||||
rpe = -1
|
||||
except KeyError:
|
||||
rpe = -1
|
||||
|
||||
try:
|
||||
ps = form.cleaned_data['plannedsession']
|
||||
@@ -4386,6 +4436,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
||||
row.weightcategory = weightcategory
|
||||
row.adaptiveclass = adaptiveclass
|
||||
row.notes = notes
|
||||
row.rpe = rpe
|
||||
row.duration = duration
|
||||
row.distance = distance
|
||||
row.boattype = boattype
|
||||
@@ -4829,6 +4880,10 @@ def workout_upload_api(request):
|
||||
t = form.cleaned_data['title']
|
||||
boattype = form.cleaned_data['boattype']
|
||||
workouttype = form.cleaned_data['workouttype']
|
||||
try:
|
||||
rpe = form.cleaned_data['rpe']
|
||||
except KeyError:
|
||||
rpe = -1
|
||||
if rowerform.is_valid():
|
||||
u = rowerform.cleaned_data['user']
|
||||
r = getrower(u)
|
||||
@@ -4884,6 +4939,7 @@ def workout_upload_api(request):
|
||||
boattype=boattype,
|
||||
makeprivate=makeprivate,
|
||||
title = t,
|
||||
rpe=rpe,
|
||||
notes=notes,
|
||||
uploadoptions=post_data,
|
||||
)
|
||||
@@ -5004,6 +5060,13 @@ def workout_upload_view(request,
|
||||
except KeyError:
|
||||
boattype = '1x'
|
||||
|
||||
try:
|
||||
rpe = docformoptions['rpe']
|
||||
if not rpe:
|
||||
rpe = -1
|
||||
except KeyError:
|
||||
rpe = -1
|
||||
|
||||
try:
|
||||
notes = docformoptions['notes']
|
||||
except KeyError:
|
||||
@@ -5081,6 +5144,10 @@ def workout_upload_view(request,
|
||||
t = form.cleaned_data['title']
|
||||
workouttype = form.cleaned_data['workouttype']
|
||||
boattype = form.cleaned_data['boattype']
|
||||
try:
|
||||
rpe = form.cleaned_data['rpe']
|
||||
except KeyError:
|
||||
rpe = -1
|
||||
|
||||
request.session['docformoptions'] = {
|
||||
'workouttype':workouttype,
|
||||
@@ -5121,6 +5188,7 @@ def workout_upload_view(request,
|
||||
'upload_to_TrainingPeaks':upload_to_tp,
|
||||
'landingpage':landingpage,
|
||||
'boattype': boattype,
|
||||
'rpe':rpe,
|
||||
'workouttype': workouttype,
|
||||
}
|
||||
|
||||
@@ -5136,6 +5204,7 @@ def workout_upload_view(request,
|
||||
workouttype=workouttype,
|
||||
workoutsource=workoutsource,
|
||||
boattype=boattype,
|
||||
rpe=rpe,
|
||||
makeprivate=makeprivate,
|
||||
title = t,
|
||||
notes=notes,
|
||||
|
||||
BIN
static/img/PM.jpg
Normal file
BIN
static/img/PM.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
Reference in New Issue
Block a user