Private
Public Access
1
0

Merge branch 'feature/trainingplans' into develop

This commit is contained in:
Sander Roosendaal
2018-09-16 08:46:08 +02:00
17 changed files with 1474 additions and 115 deletions

View File

@@ -95,5 +95,5 @@ def coursetime_paths(data,paths,finalmaxmin='min'):
entrytime = data['time'].max()
entrydistance = data['cum_dist'].max()
coursecompleted = False
return entrytime, entrydistance, coursecompleted

View File

@@ -840,6 +840,7 @@ def checkworkoutuser(user,workout):
except Rower.DoesNotExist:
return False
# Check if user is coach or rower
def checkaccessuser(user,rower):
try:
@@ -979,11 +980,60 @@ class TrainingTargetForm(ModelForm):
class TrainingPlan(models.Model):
rower = models.ForeignKey(Rower)
name = models.CharField(max_length=150,blank=True)
target = models.ForeignKey(TrainingTarget,blank=True)
target = models.ForeignKey(TrainingTarget,blank=True,null=True)
startdate = models.DateField(default=timezone.now)
enddate = models.DateField(
default=half_year_from_now)
def __unicode__(self):
name = self.name
startdate = self.startdate
enddate = self.enddate
firstname = self.rower.user.first_name
lastname = self.rower.user.last_name
stri = u'Training Plan for {firstname} {lastname} {s} - {e}: {name}'.format(
s = startdate.strftime('%Y-%m-%d'),
e = enddate.strftime('%Y-%m-%d'),
firstname = firstname,
lastname = lastname,
name=name
)
return stri
def save(self, *args, **kwargs):
if self.enddate < self.startdate:
startdate = self.startdate
enddate = self.enddate
self.startdate = enddate
self.enddate = startdate
otherplans = TrainingPlan.objects.filter(rower=self.rower).exclude(pk=self.pk).order_by("-startdate")
for otherplan in otherplans:
if otherplan.startdate <= self.enddate and otherplan.startdate >= self.startdate:
self.enddate = otherplan.startdate-datetime.timedelta(days=1)
if otherplan.enddate >= self.startdate and otherplan.enddate <= self.enddate:
self.startdate = otherplan.enddate+datetime.timedelta(days=1)
if not self.enddate <= self.startdate:
super(TrainingPlan,self).save(*args, **kwargs)
macrocycles = TrainingMacroCycle.objects.filter(plan = self)
if not macrocycles:
m = TrainingMacroCycle(
plan = self,
name = 'Filler',
startdate = self.startdate,
enddate = self.enddate,
)
m.save()
else:
createmacrofillers(self)
class TrainingPlanForm(ModelForm):
class Meta:
model = TrainingPlan
@@ -1009,6 +1059,253 @@ cycletypechoices = (
('userdefined','User Defined')
)
def createmacrofillers(plan):
fillers = TrainingMacroCycle.objects.filter(
plan = plan, type = 'filler'
)
for f in fillers:
f.delete()
cycles = TrainingMacroCycle.objects.filter(
plan = plan
).order_by("-startdate")
if not cycles:
macr = TrainingMacroCycle(
plan=plan,
startdate = plan.startdate,
enddate = plan.enddate,
type='filler',
name='Filler'
)
macr.save()
thedate = plan.enddate
while cycles:
if cycles[0].enddate < thedate:
macr = TrainingMacroCycle(
plan=plan,
startdate = cycles[0].enddate+datetime.timedelta(days=1),
enddate = thedate,
type='filler',
name='Filler'
)
macr.save()
thedate = cycles[0].startdate-datetime.timedelta(days=1)
cycles = cycles[1:]
cycles = TrainingMacroCycle.objects.filter(
plan = plan
).order_by("startdate")
if cycles[0].startdate > plan.startdate:
macr = TrainingMacroCycle(
plan=plan,
startdate = plan.startdate,
enddate = cycles[0].startdate-datetime.timedelta(days=1),
type='filler',
name='Filler'
)
macr.save()
def createmesofillers(plan):
fillers = TrainingMesoCycle.objects.filter(
plan = plan, type = 'filler'
)
for f in fillers:
f.delete()
cycles = TrainingMesoCycle.objects.filter(
plan = plan
).order_by("-startdate")
if not cycles:
macr = TrainingMesoCycle(
plan = plan,
startdate = plan.startdate,
enddate = plan.enddate,
type='filler',
name='Filler'
)
macr.save()
thedate = plan.enddate
while cycles:
if cycles[0].enddate < thedate:
macr = TrainingMesoCycle(
plan=plan,
startdate = cycles[0].enddate+datetime.timedelta(days=1),
enddate = thedate,
type='filler',
name='Filler'
)
macr.save()
thedate = cycles[0].startdate-datetime.timedelta(days=1)
cycles = cycles[1:]
cycles = TrainingMesoCycle.objects.filter(
plan = plan
).order_by("startdate")
if cycles[0].startdate > plan.startdate:
macr = TrainingMesoCycle(
plan=plan,
startdate = plan.startdate,
enddate = cycles[0].startdate-datetime.timedelta(days=1),
type='filler',
name='Filler'
)
macr.save()
def createmicrofillers(plan):
fillers = TrainingMicroCycle.objects.filter(
plan = plan, type = 'filler'
)
for f in fillers:
f.delete()
cycles = TrainingMicroCycle.objects.filter(
plan = plan
).order_by("-startdate")
if not cycles:
macr = TrainingMicroCycle(
plan=plan,
startdate = plan.startdate,
enddate = plan.enddate,
type='filler',
name='Filler'
)
macr.save()
thedate = plan.enddate
while cycles:
if cycles[0].enddate < thedate:
macr = TrainingMicroCycle(
plan=plan,
startdate = cycles[0].enddate+datetime.timedelta(days=1),
enddate = thedate,
type='filler',
name='Filler'
)
macr.save()
thedate = cycles[0].startdate-datetime.timedelta(days=1)
cycles = cycles[1:]
cycles = TrainingMicroCycle.objects.filter(
plan = plan
).order_by("startdate")
if cycles[0].startdate > plan.startdate:
macr = TrainingMicroCycle(
plan=plan,
startdate = plan.startdate,
enddate = cycles[0].startdate-datetime.timedelta(days=1),
type='filler',
name='Filler'
)
macr.save()
def microcyclecheckdates(plan):
cycles = TrainingMicroCycle.objects.filter(
plan=plan
).order_by("-startdate")
thedate = plan.enddate
while cycles:
if cycles[0].enddate < plan.startdate:
cycles[0].delete()
if cycles[0].startdate > plan.enddate:
cycles[0].delete()
if cycles[0].enddate > thedate:
cycles[0].enddate = thedate
cycles[0].save()
thedate = cycles[0].startdate-datetime.timedelta(days=1)
cycles = cycles[1:]
cycles = TrainingMicroCycle.objects.filter(
plan=plan
).order_by("startdate")
thedate = plan.startdate
while cycles:
if cycles[0].startdate < thedate:
cycles[0].startdate = thedate
cycles[0].save()
try:
thedate = cycles[1].startdate-datetime.timedelta(days=1)
except IndexError:
pass
cycles = cycles[1:]
def mesocyclecheckdates(plan):
cycles = TrainingMesoCycle.objects.filter(
plan=plan
).order_by("-startdate")
thedate = plan.enddate
while cycles:
if cycles[0].enddate < plan.startdate:
cycles[0].delete()
if cycles[0].startdate > plan.enddate:
cycles[0].delete()
if cycles[0].enddate > thedate:
cycles[0].enddate = thedate
cycles[0].save()
thedate = cycles[0].startdate-datetime.timedelta(days=1)
cycles = cycles[1:]
cycles = TrainingMesoCycle.objects.filter(
plan=plan
).order_by("startdate")
thedate = plan.startdate
while cycles:
if cycles[0].startdate < thedate:
cycles[0].startdate = thedate
cycles[0].save()
try:
thedate = cycles[1].startdate-datetime.timedelta(days=1)
except IndexError:
pass
cycles = cycles[1:]
def macrocyclecheckdates(plan):
cycles = TrainingMacroCycle.objects.filter(
plan=plan
).order_by("-startdate")
thedate = plan.enddate
while cycles:
if cycles[0].enddate < plan.startdate:
cycles[0].delete()
if cycles[0].startdate > plan.enddate:
cycles[0].delete()
if cycles[0].enddate > thedate:
cycles[0].enddate = thedate
cycles[0].save()
thedate = cycles[0].startdate-datetime.timedelta(days=1)
cycles = cycles[1:]
cycles = TrainingMacroCycle.objects.filter(
plan=plan
).order_by("startdate")
thedate = plan.startdate
while cycles:
if cycles[0].startdate < thedate:
cycles[0].startdate = thedate
cycles[0].save()
try:
thedate = cycles[1].startdate-datetime.timedelta(days=1)
except IndexError:
pass
cycles = cycles[1:]
class TrainingMacroCycle(models.Model):
plan = models.ForeignKey(TrainingPlan)
name = models.CharField(max_length=150,blank=True)
@@ -1016,10 +1313,85 @@ class TrainingMacroCycle(models.Model):
enddate = models.DateField(
default=half_year_from_now)
notes = models.TextField(max_length=300,blank=True)
type = models.CharField(default='filler',
choices=cycletypechoices,
max_length=150)
plantime = models.IntegerField(default=0,verbose_name='Planned Duration')
plandistance = models.IntegerField(default=0,verbose_name='Planned Distance')
planrscore = models.IntegerField(default=0,verbose_name='Planned rScore')
plantrimp = models.IntegerField(default=0,verbose_name='Planned TRIMP')
actualtime = models.IntegerField(default=0,verbose_name='Actual Duration')
actualdistance = models.IntegerField(default=0,verbose_name='Actual Distance')
actualrscore = models.IntegerField(default=0,verbose_name='Actual rScore')
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
def __unicode__(self):
stri = 'Macro Cycle - {n} ({sd} - {ed})'.format(
n = self.name,
sd = self.startdate,
ed = self.enddate,
)
return stri
def save(self, *args, **kwargs):
if self.enddate < self.startdate:
startdate = self.startdate
enddate = self.enddate
self.startdate = enddate
self.enddate = startdate
fillers = TrainingMacroCycle.objects.filter(
plan=self.plan,type='filler')
for f in fillers:
f.delete()
if self.enddate > self.plan.enddate:
self.enddate = self.plan.enddate
if self.startdate < self.plan.startdate:
self.startdate = self.plan.startdate
othercycles = TrainingMacroCycle.objects.filter(
plan=self.plan).exclude(pk=self.pk).order_by("-startdate")
for othercycle in othercycles:
if othercycle.startdate <= self.enddate and othercycle.startdate >= self.startdate:
self.enddate = othercycle.startdate-datetime.timedelta(days=1)
if othercycle.enddate >= self.startdate and othercycle.enddate <= self.enddate:
self.startdate = othercycle.enddate+datetime.timedelta(days=1)
if not self.enddate <= self.startdate:
super(TrainingMacroCycle,self).save(*args, **kwargs)
mesocycles = TrainingMesoCycle.objects.filter(plan = self)
if not mesocycles:
meso = TrainingMesoCycle(
plan = self,
name = 'Filler',
startdate = self.startdate,
enddate = self.enddate,
)
meso.save()
else:
createmesofillers(self)
class TrainingMacroCycleForm(ModelForm):
class Meta:
model = TrainingMacroCycle
fields = ['name','startdate','enddate','notes']
widgets = {
'startdate': AdminDateWidget(),
'enddate': AdminDateWidget()
}
class TrainingMesoCycle(models.Model):
plan = models.ForeignKey(TrainingMacroCycle)
name = models.CharField(max_length=150,blank=True)
@@ -1031,6 +1403,69 @@ class TrainingMesoCycle(models.Model):
choices=cycletypechoices,
max_length=150)
plantime = models.IntegerField(default=0,verbose_name='Planned Duration')
plandistance = models.IntegerField(default=0,verbose_name='Planned Distance')
planrscore = models.IntegerField(default=0,verbose_name='Planned rScore')
plantrimp = models.IntegerField(default=0,verbose_name='Planned TRIMP')
actualtime = models.IntegerField(default=0,verbose_name='Actual Duration')
actualdistance = models.IntegerField(default=0,verbose_name='Actual Distance')
actualrscore = models.IntegerField(default=0,verbose_name='Actual rScore')
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
def __unicode__(self):
stri = 'Meso Cycle - {n} ({sd} - {ed})'.format(
n = self.name,
sd = self.startdate,
ed = self.enddate,
)
return stri
def save(self, *args, **kwargs):
if self.enddate < self.startdate:
startdate = self.startdate
enddate = self.enddate
self.startdate = enddate
self.enddate = startdate
fillers = TrainingMesoCycle.objects.filter(
plan=self.plan,type='filler')
for f in fillers:
f.delete()
if self.enddate > self.plan.enddate:
self.enddate = self.plan.enddate
if self.startdate < self.plan.startdate:
self.startdate = self.plan.startdate
othercycles = TrainingMesoCycle.objects.filter(
plan=self.plan).exclude(pk=self.pk).order_by("-startdate")
for othercycle in othercycles:
if othercycle.startdate <= self.enddate and othercycle.startdate >= self.startdate:
self.enddate = othercycle.startdate-datetime.timedelta(days=1)
if othercycle.enddate >= self.startdate and othercycle.enddate <= self.enddate:
self.startdate = othercycle.enddate+datetime.timedelta(days=1)
if not self.enddate <= self.startdate:
super(TrainingMesoCycle,self).save(*args, **kwargs)
microcycles = TrainingMicroCycle.objects.filter(plan = self)
if not microcycles:
micro = TrainingMicroCycle(
plan = self,
name = 'Filler',
startdate = self.startdate,
enddate = self.enddate,
)
micro.save()
else:
createmicrofillers(self)
class TrainingMicroCycle(models.Model):
plan = models.ForeignKey(TrainingMesoCycle)
@@ -1043,15 +1478,81 @@ class TrainingMicroCycle(models.Model):
choices=cycletypechoices,
max_length=150)
plantime = models.IntegerField(default=0,verbose_name='Planned Duration')
plandistance = models.IntegerField(default=0,verbose_name='Planned Distance')
planrscore = models.IntegerField(default=0,verbose_name='Planned rScore')
plantrimp = models.IntegerField(default=0,verbose_name='Planned TRIMP')
# Needs some error checking
# - Microcycles should not overlap with other microcycles, same for MesoCycles, MacroCycles
# - When a TrainingPlan is created, it should create 1 "collector" Macro, Meso & MicroCycle - this is invisible for users who choose to not use cycles
# - When a new Microcycle is inserted, the "collector" cycle is automatically adjusted to "go out of the way" of the new MicroCycle - and similar for Macro & Meso
# - If the entire MesoCycle is filled with user defined MicroCycles - there are no "filler" MicroCycles
# - Sessions are automatically linked to the correct Cycles based on their start/end date - no need for a hard link
actualtime = models.IntegerField(default=0,verbose_name='Actual Duration')
actualdistance = models.IntegerField(default=0,verbose_name='Actual Distance')
actualrscore = models.IntegerField(default=0,verbose_name='Actual rScore')
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
def __unicode__(self):
stri = 'Micro Cycle - {n} ({sd} - {ed})'.format(
n = self.name,
sd = self.startdate,
ed = self.enddate,
)
return stri
def save(self, *args, **kwargs):
if self.enddate < self.startdate:
startdate = self.startdate
enddate = self.enddate
self.startdate = enddate
self.enddate = startdate
fillers = TrainingMicroCycle.objects.filter(
plan=self.plan,type='filler')
for f in fillers:
f.delete()
if self.enddate > self.plan.enddate:
self.enddate = self.plan.enddate
if self.startdate < self.plan.startdate:
self.startdate = self.plan.startdate
othercycles = TrainingMicroCycle.objects.filter(
plan=self.plan).exclude(pk=self.pk).order_by("-startdate")
for othercycle in othercycles:
if othercycle.startdate <= self.enddate and othercycle.startdate >= self.startdate:
self.enddate = othercycle.startdate-datetime.timedelta(days=1)
if othercycle.enddate >= self.startdate and othercycle.enddate <= self.enddate:
self.startdate = othercycle.enddate+datetime.timedelta(days=1)
if not self.enddate <= self.startdate:
super(TrainingMicroCycle,self).save(*args, **kwargs)
class TrainingMesoCycleForm(ModelForm):
class Meta:
model = TrainingMesoCycle
fields = ['name','startdate','enddate','notes']
widgets = {
'startdate': AdminDateWidget(),
'enddate': AdminDateWidget()
}
class TrainingMicroCycleForm(ModelForm):
class Meta:
model = TrainingMicroCycle
fields = ['name','startdate','enddate','notes']
widgets = {
'startdate': AdminDateWidget(),
'enddate': AdminDateWidget()
}
# Cycle error checking goes in forms
# model for Planned Session (Workout, Challenge, Test)
class PlannedSession(models.Model):

View File

@@ -10,7 +10,7 @@ import uuid
from django.conf import settings
import pytz
from utils import myqueue,calculate_age,totaltime_sec_to_string
import re
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
@@ -296,52 +296,28 @@ def is_session_complete_ws(ws,ps):
if record.coursecompleted:
ratio = record.distance/ps.sessionvalue
return ratio,'completed',completiondate
if ps.course:
(
coursetime,
coursemeters,
coursecompleted
) = get_time_course(ws,ps.course)
if coursecompleted:
return 1.0,'completed',completiondate
else:
return ratio,'partial',completiondate
else:
if ps.criterium == 'exact':
if ratio == 1.0:
return ratio,'completed',completiondate
else:
if not completiondate:
completiondate = ws.reverse()[0].date
return ratio,'partial',completiondate
elif ps.criterium == 'minimum':
if ratio >= 1.0:
return ratio,'completed',completiondate
else:
if not completiondate:
completiondate = ws.reverse()[0].date
return ratio,'partial',completiondate
else:
if ratio>cratiomin and ratio<cratiomax:
return ratio,'completed',completiondate
else:
ratio = record.distance/ps.sessionvalue
return ratio,'partial',completiondate
return (0,'partial',None)
elif ps.sessiontype == 'coursetest':
vs = CourseTestResult.objects.filter(plannedsession=ps)
wids = [w.id for w in ws]
for record in vs:
if record.workoutid in wids:
if record.coursecompleted:
ratio = record.distance/ps.sessionvalue
ratio = record.distance/float(ps.sessionvalue)
return ratio,'completed',completiondate
else:
ratio = record.distance/float(ps.sessionvalue)
return ratio,'partial',completiondate
# we're still here - no record, need to create one
if ws:
record = CourseTestResult(
userid=ws[0].user.id,
plannedsession=ps,
workoutid=ws[0].id,
duration=dt.time(0,0),
coursecompleted=False,
)
@@ -349,38 +325,9 @@ def is_session_complete_ws(ws,ps):
job = myqueue(queue,handle_check_race_course,ws[0].csvfilename,
ws[0].id,ps.course.id,record.id,
mode='coursetest')
if ps.course:
(
coursetime,
coursemeters,
coursecompleted
) = courses.get_time_course(ws,ps.course)
if coursecompleted:
return 1.0,'completed',completiondate
else:
return ratio,'partial',completiondate
else:
if ps.criterium == 'exact':
if ratio == 1.0:
return ratio,'completed',completiondate
else:
if not completiondate:
completiondate = ws.reverse()[0].date
return ratio,'partial',completiondate
elif ps.criterium == 'minimum':
if ratio >= 1.0:
return ratio,'completed',completiondate
else:
if not completiondate:
completiondate = ws.reverse()[0].date
return ratio,'partial',completiondate
else:
if ratio>cratiomin and ratio<cratiomax:
return ratio,'completed',completiondate
else:
return ratio,'partial',completiondate
return (0,'not done',None)
else:
if not completiondate:
@@ -391,6 +338,7 @@ def is_session_complete_ws(ws,ps):
def is_session_complete(r,ps):
status = 'not done'
if r not in ps.rower.all():
return 0,'not assigned',None
@@ -426,6 +374,8 @@ def remove_rower_session(r,ps):
def get_dates_timeperiod(timeperiod):
# set start end date according timeperiod
daterangetester = re.compile('^(\d+-\d+-\d+)\/(\d+-\d+-\d+)')
if timeperiod=='today':
startdate=date.today()
enddate=date.today()
@@ -466,6 +416,19 @@ def get_dates_timeperiod(timeperiod):
enddate = startdate+timezone.timedelta(days=32)
enddate = enddate.replace(day=1)
enddate = enddate-timezone.timedelta(days=1)
elif daterangetester.match(timeperiod):
startdatestring = daterangetester.match(timeperiod).group(1)
enddatestring = daterangetester.match(timeperiod).group(2)
try:
startdate = dt.datetime.strptime(startdatestring,'%Y-%m-%d').date()
enddate = dt.datetime.strptime(enddatestring,'%Y-%m-%d').date()
if startdate > enddate:
startdate2 = enddate
enddate = startdate
startdate = startdate2
except ValueError:
startdate = date.today()
enddate = date.today()
else:
startdate = date.today()
enddate = date.today()

View File

@@ -255,7 +255,7 @@ def handle_check_race_course(self,
rowdata.rename(columns = {
' latitude':'latitude',
' longitude':'longitude',
' ElapsedTime (sec)': 'time',
'TimeStamp (sec)': 'time',
}, inplace=True)
rowdata.fillna(method='backfill',inplace=True)
@@ -299,9 +299,9 @@ def handle_check_race_course(self,
cseconds = []
cmeters = []
ccomplete = []
for startt in entrytimes:
rowdata2 = rowdata[rowdata['time']>(startt-10.)]
(
@@ -322,6 +322,7 @@ def handle_check_race_course(self,
coursetimeseconds = coursetimeseconds-coursetimefirst
coursemeters = coursemeters-coursemetersfirst
cseconds.append(coursetimeseconds)
cmeters.append(coursemeters)
ccomplete.append(coursecompleted)
@@ -335,6 +336,7 @@ def handle_check_race_course(self,
records = records[records['coursecompleted'] == True]
if len(records):
coursecompleted = True
mintime = records['coursetimeseconds'].min()

View File

@@ -138,7 +138,19 @@
Analyse power vs piece duration to make predictions, for erg pieces.
</p>
</div>
<div class="grid_2 suffix_2 alpha">
<div class="grid_2">
<p>
{% if user|is_planmember %}
<a class="button blue small" href="/rowers/fitness-progress">Power Progress</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Power Progress</a>
{% endif %}
</p>
<p>
Monitoring power duration evidence from all your workouts. Feel free to explore.
</p>
</div>
<div class="grid_2 omega">
<p>
{% if user|is_planmember %}
<a class="button blue small" href="/rowers/laboratory">The Labs</a>

View File

@@ -24,13 +24,13 @@
<div class="grid_2 alpha">
<p>
{% if user|is_planmember %}
<a class="button blue small" href="/rowers/fitness-progress">Power Progress</a>
<a class="button blue small" href="/rowers/createplan">Training Target</a>
{% else %}
<a class="button blue small" href="/rowers/promembership">Power Progress</a>
<a class="button blue small" href="/rowers/promembership">Training Target</a>
{% endif %}
</p>
<p>
Monitoring power duration evidence from all your workouts. Feel free to explore.
Experiments with a training target and plan builder
</p>
</div>
</div>

View File

@@ -65,6 +65,7 @@
</thead>
<tbody>
{% for result in ranking %}
{% if result|lookup:'coursecompleted' %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ result|lookup:'name' }}</td>
@@ -73,6 +74,7 @@
<td>{{ result|lookup:'date'|date:"Y-m-d" }}</td>
<td>{{ result|lookup:'type' }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>

View File

@@ -1,14 +1,20 @@
{% load rowerfilters %}
<div class="grid_2 alpha">
<p>
{% if timeperiod and rower %}
<a class="button gray small" href="/rowers/sessions/{{ timeperiod }}/rower/{{ rower.id }}">Plan Overview</a>
{% elif timeperiod %}
<a class="button gray small" href="/rowers/sessions/{{ timeperiod }}">Plan Overview</a>
{% else %}
<a class="button gray small" href="/rowers/sessions">Plan Overview</a>
{% endif %}
</p>
<div class="grid_2 dropdown alpha">
<button class="grid_2 alpha button gray small dropbtn">Overview</button>
<div class="dropdown-content">
{% if timeperiod and rower %}
<a class="button gray small" href="/rowers/sessions/{{ timeperiod }}/rower/{{ rower.id }}">Sessions Overview</a>
{% elif timeperiod %}
<a class="button gray small" href="/rowers/sessions/{{ timeperiod }}">Sessions Overview</a>
{% else %}
<a class="button gray small" href="/rowers/sessions">Sessions Overview</a>
{% endif %}
{% if plan %}
<a class="button gray small" href="/rowers/plan/{{ plan.id }}">Plan Overview</a>
{% endif %}
</div>
</div>
</div>
<div class="grid_2">
<p>

View File

@@ -0,0 +1,221 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Rowsandall Training Plans{% endblock %}
{% block scripts %}
{% endblock %}
{% block content %}
<style>
#mypointer {
cursor: pointer;
}
</style>
<div class="grid_12">
<div class="grid_12 alpha">
<h1>Training Plan - {{ plan.name }}</h1>
<p>This plan starts on {{ plan.startdate }} and ends on {{ plan.enddate }}. The training plan target is: {{ plan.target.name }} on {{ plan.target.date }}.</p>
<p><a href="/rowers/editplan/{{ plan.id }}">Edit the plan</a></p>
</div>
<div class="grid_4 alpha">
<h2>Macro Cycles</h2>
</div>
<div class="grid_4 alpha">
<h2>Meso Cycles</h2>
</div>
<div class="grid_4">
<h2>Micro Cycles</h2>
</div>
</div>
<div class="grid_12 alpha">
{% now "Y-m-d" as todays_date %}
{% for key,macrocycle in cycles.items %}
<div class="grid_12 alpha">
{% if macrocycle.0.type == 'filler' %}
<div class="grid_4 filler alpha">
{% else %}
<div class="grid_4 palegreen alpha">
{% endif %}
<div class="padded">
<table width="100%">
<tr>
<th colspan="4">
{{ macrocycle.0.name }} ({{ macrocycle.0.startdate }} - {{ macrocycle.0.enddate }})
</th>
</tr>
<tr>
<td></td>
<td>dist (m)</td>
<td>t (min)</td>
<td>rScore</td>
<td>TRIMP</td>
</tr>
<tr>
<td>plan</td>
<td>{{ macrocycle.0.plandistance }}</td>
<td>{{ macrocycle.0.plantime }}</td>
<td>{{ maccrocycle.0.planrscore }}</td>
<td>{{ macrocycle.0.plantrimp }}</td>
</tr>
<tr>
<td>actual</td>
<td>{{ macrocycle.0.actualdistance }}</td>
<td>{{ macrocycle.0.actualtime }}</td>
<td>{{ macrocycle.0.actualrscore }}</td>
<td>{{ macrocycle.0.actualtrimp }}</td>
</tr>
{% if todays_date <= macrocycle.0.enddate|date:"Y-m-d" %}
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<td colspan="4">
<a href="/rowers/macrocycle/{{ macrocycle.0.id }}">edit</a>
/
<a href="/rowers/deletemacrocycle/{{ macrocycle.0.id }}">delete</a>
/
<a href='/rowers/sessions/{{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}'>sessions</a>
</td>
</tr>
{% endif %}
</table>
</div>
</div>
<div class="grid_8 alpha">
{% for key, mesocycle in macrocycle.1.items %}
{% if mesocycle.0.type == 'filler' %}
<div class="grid_4 filler alpha">
{% else %}
<div class="grid_4 lightsalmon alpha">
{% endif %}
<div class="padded">
<table width="100%">
<tr>
<th colspan="4">
{{ mesocycle.0.name }} ({{ mesocycle.0.startdate }} - {{ mesocycle.0.enddate }})
</th>
</tr>
{% if mesocycle.0.plan.type == 'userdefined' %}
<tr>
<td></td>
<td>dist (m)</td>
<td>t (min)</td>
<td>rScore</td>
<td>TRIMP</td>
</tr>
<tr>
<td>plan</td>
<td>{{ mesocycle.0.plandistance }}</td>
<td>{{ mesocycle.0.plantime }}</td>
<td>{{ mesocycle.0.planrscore }}</td>
<td>{{ mesocycle.0.plantrimp }}</td>
</tr>
<tr>
<td>actual</td>
<td>{{ mesocycle.0.actualdistance }}</td>
<td>{{ mesocycle.0.actualtime }}</td>
<td>{{ mesocycle.0.actualrscore }}</td>
<td>{{ mesocycle.0.actualtrimp }}</td>
</tr>
{% if todays_date <= mesocycle.0.enddate|date:"Y-m-d" %}
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<td colspan="4">
<a href="/rowers/microcycle/{{ mesocycle.0.id }}">edit</a>
/
<a href="/rowers/deletemicrocycle/{{ mesocycle.0.id }}">delete</a>
/
<a href='/rowers/sessions/{{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}'>sessions</a>
</td>
</tr>
{% endif %}
{% endif %}
</table>
</div>
</div>
<div class="grid_4 omega">
{% for microcycle in mesocycle.1 %}
{% if microcycle.type == 'filler' %}
<div class="grid_4 filler">
{% else %}
<div class="grid_4 paleblue ">
{% endif %}
<div class="padded">
<table width="100%">
<tr>
<th colspan="4">
{{ microcycle.name }} ({{ microcycle.startdate }} - {{ microcycle.enddate }})
</th>
</tr>
{% if microcycle.plan.type == 'userdefined' %}
<tr>
<td></td>
<td>dist (m)</td>
<td>t (min)</td>
<td>rScore</td>
<td>TRIMP</td>
</tr>
<tr>
<td>plan</td>
<td>{{ microcycle.plandistance }}</td>
<td>{{ microcycle.plantime }}</td>
<td>{{ microcycle.planrscore }}</td>
<td>{{ microcycle.plantrimp }}</td>
</tr>
<tr>
<td>actual</td>
<td>{{ microcycle.actualdistance }}</td>
<td>{{ microcycle.actualtime }}</td>
<td>{{ microcycle.actualrscore }}</td>
<td>{{ microcycle.actualtrimp }}</td>
</tr>
{% if todays_date <= microcycle.enddate|date:"Y-m-d" %}
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<td colspan="4">
<a href="/rowers/microcycle/{{ microcycle.id }}">edit</a>
/
<a href="/rowers/deletemicrocycle/{{ microcycle.id }}">delete</a>
/
<a href='/rowers/sessions/{{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}'>sessions</a>
</td>
</tr>
{% endif %}
{% endif %}
</table>
</div>
</div>
{% endfor %}
</div>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<div class="grid_12">
<p>Click on the plan cycles to edit their names, start and end dates. The gray "filler"
cycles are generated, adjusted and deleted automatically to ensure the entire plan
duration is covered with non-overlapping cycles.
Once you edit a filler cycle, it become a user-defined cycle, which cannot be deleted
by the system.</p>
<p>Filler cycles which have a filler cycle as a parent cannot be edited
or deleted. You have to edit the parent cycle first. The reason is
that children of filler cycles are not safe. They are deleted when
their parent is deleted by the system.</p>
<p>Click on "Sessions" in the cycle of your interest to see details
of the individual training sessions planned for this period.</p>
<p>A good way to organize the plan is to think of micro cycles as training weeks. Macro cycles
are typically used to address specific phases of preparation and to indicate the racing
season and may span several months.
Meso cycles can be used to group sequences of three to five light, medium and
hard weeks. It is recommended to work from left to right, starting with the macro cycles.</p>
</div>
{% endblock %}

View File

@@ -15,7 +15,23 @@
}
</style>
<div class="grid_12">
<div class="grid_12 alpha">
{% if user.is_authenticated and user|is_manager %}
<div class="grid_2 prefix_8 dropdown">
<button class="grid_2 alpha button green small dropbtn">
{{ rower.user.first_name }} {{ rower.user.last_name }}
</button>
<div class="dropdown-content">
{% for member in user|team_members %}
<a class="button green small" href="/rowers/createplan/{{ member.id }}">{{ member.first_name }} {{ member.last_name }}</a>
{% endfor %}
</div>
</div>
{% endif %}
</div>
<div class="grid_12 alpha">
<div id="targets_table" class="grid_8 alpha">
<h1>Training Targets</h1>
@@ -34,6 +50,8 @@
<td> {{ target.date }}</td>
<td> {{ target.name }}</td>
<td> {{ target.notes }}</td>
<td> <a href="/rowers/edittarget/{{ target.id }}">Edit</a>
<td> <a href="/rowers/deletetarget/{{ target.id }}">Delete</a>
</tr>
{% endfor %}
</tbody>
@@ -62,8 +80,8 @@
</div>
<div class="grid_12">
<div class="grid_12 alpha">
<div id="courses_table" class="grid_8 alpha">
<h1>Plans</h1>
@@ -81,7 +99,10 @@
<tr>
<td> {{ plan.startdate }} </td>
<td> {{ plan.enddate }}</td>
<td> {{ plan.name }}</td>
<td><a href="/rowers/plan/{{ plan.id }}">{{ plan.name }}</a></td>
<td> <a href="/rowers/editplan/{{ plan.id }}">Edit</a></td>
<td> <a href="/rowers/plan/{{ plan.id }}">Plan</a></td>
<td> <a href="/rowers/deleteplan/{{ plan.id }}">Delete</a></td>
</tr>
{% endfor %}
</tbody>

View File

@@ -0,0 +1,30 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Rowsandall Training Plans{% endblock %}
{% block scripts %}
{% endblock %}
{% block content %}
<style>
#mypointer {
cursor: pointer;
}
</style>
<div class="grid_12 alpha">
<form action="" method="post">
{% csrf_token %}
<p>Are you sure you want to delete <i>{{ object }}</i>?</p>
<div id="formbutton" class="grid_1 prefix_2">
<input class="button red" type="submit" value="Confirm">
</div>
</form>
</div>
{% endblock %}

View File

@@ -0,0 +1,32 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Rowsandall Training Plans{% endblock %}
{% block scripts %}
{% endblock %}
{% block content %}
<style>
#mypointer {
cursor: pointer;
}
</style>
<div class="grid_12">
<form action="" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<div class="grid_1 prefix_2 suffix_9 alpha">
<input class="button green" type="submit" value="Save">
</div>
</form>
</div>
{% endblock %}

View File

@@ -275,3 +275,10 @@ def future_registered(race,r):
is_complete, has_registered = race_rower_status(r,race)
is_open = race.evaluation_closure > timezone.now()
return has_registered and not is_complete and is_open
@property
def is_past_due(self):
return datetime.date.today() > self.date
@property
def is_not_past_due(self):
return datetime.date.today() <= self.date

View File

@@ -20,7 +20,6 @@ from subprocess import call
import re
from verbalexpressions import VerEx
import re
import django_rq
queue = django_rq.get_queue('default')

View File

@@ -420,7 +420,19 @@ urlpatterns = [
url(r'^workout/compare/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>[\w\ ]+.*)/$',views.workout_comparison_view2),
url(r'^test\_callback',views.rower_process_testcallback),
url(r'^createplan$',views.rower_create_trainingplan),
url(r'^createplan/(?P<id>\d+)$',views.rower_create_trainingplan),
url(r'^createplan/(?P<userid>\d+)$',views.rower_create_trainingplan),
url(r'^deleteplan/(?P<pk>\d+)$',views.TrainingPlanDelete.as_view()),
url(r'^deletemicrocycle/(?P<pk>\d+)$',views.MicroCycleDelete.as_view()),
url(r'^deletemesocycle/(?P<pk>\d+)$',views.MesoCycleDelete.as_view()),
url(r'^deletemacrocycle/(?P<pk>\d+)$',views.MacroCycleDelete.as_view()),
# url(r'^deleteplan/(?P<id>\d+)$',views.rower_delete_trainingplan),
url(r'^plan/(?P<id>\d+)$',views.rower_trainingplan_view),
url(r'^macrocycle/(?P<pk>\d+)$',views.TrainingMacroCycleUpdate.as_view()),
url(r'^mesocycle/(?P<pk>\d+)$',views.TrainingMesoCycleUpdate.as_view()),
url(r'^microcycle/(?P<pk>\d+)$',views.TrainingMicroCycleUpdate.as_view()),
url(r'^deletetarget/(?P<id>\d+)$',views.rower_delete_trainingtarget),
url(r'^editplan/(?P<pk>\d+)$',views.TrainingPlanUpdate.as_view()),
url(r'^edittarget/(?P<pk>\d+)$',views.TrainingTargetUpdate.as_view()),
url(r'^workout/(?P<id>\d+)/test\_strokedata$',views.strokedataform),
url(r'^sessions/teamcreate$',views.plannedsession_teamcreate_view),

View File

@@ -27,6 +27,9 @@ import codecs
import isodate
from django.shortcuts import render
from django.views.generic.edit import UpdateView,DeleteView
from django.http import (
HttpResponse, HttpResponseRedirect,
HttpResponseForbidden, HttpResponseNotAllowed,
@@ -42,7 +45,8 @@ from rowers.forms import (
VirtualRaceSelectForm,WorkoutRaceSelectForm,CourseSelectForm,
RaceResultFilterForm,PowerIntervalUpdateForm
)
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse, reverse_lazy
from django.core.exceptions import PermissionDenied
from django.template import RequestContext
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
@@ -68,6 +72,10 @@ from rowers.models import (
TrainingPlan,TrainingPlanForm,TrainingTarget,TrainingTargetForm,
TrainingMacroCycle,TrainingMesoCycle,TrainingMicroCycle,
TrainingTarget,TrainingTargetForm,
TrainingMacroCycleForm,createmacrofillers,
createmicrofillers, createmesofillers,
microcyclecheckdates,mesocyclecheckdates,macrocyclecheckdates,
TrainingMesoCycleForm, TrainingMicroCycleForm,
)
from rowers.models import (
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
@@ -125,6 +133,9 @@ from rowers.tasks_standalone import addcomment2
from django.contrib import messages
from async_messages import messages as a_messages
from django.contrib.admin.widgets import AdminDateWidget,AdminTimeWidget,AdminSplitDateTime
import requests
import json
from rest_framework.renderers import JSONRenderer
@@ -197,6 +208,7 @@ class JSONResponse(HttpResponse):
def getrequestrower(request,rowerid=0,userid=0,notpermanent=False):
if notpermanent == False:
if rowerid == 0 and 'rowerid' in request.session:
rowerid = request.session['rowerid']
@@ -12453,8 +12465,18 @@ def plannedsession_multiclone_view(
dateshiftform = SessionDateShiftForm()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
return render(request, 'plannedsessions_multiclone_select.html',
{'plannedsessions':sps,
'plan':trainingplan,
'dateform':dateform,
'startdate':startdate,
'enddate':enddate,
@@ -12471,6 +12493,7 @@ def plannedsession_multiclone_view(
def plannedsession_create_view(request,timeperiod='thisweek',rowerid=0):
r = getrequestrower(request,rowerid=rowerid)
startdate,enddate = get_dates_timeperiod(timeperiod)
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST)
@@ -12527,31 +12550,60 @@ def plannedsession_create_view(request,timeperiod='thisweek',rowerid=0):
fstartdate = arrow.get(request.session['fstartdate']).date()
except KeyError:
fstartdate = timezone.now().date()
if fstartdate < startdate:
fstartdate = startdate
try:
fenddate = arrow.get(request.session['fenddate']).date()
except KeyError:
fenddate = timezone.now().date()
if fenddate > enddate:
fenddate = enddate
try:
fprefdate = arrow.get(request.session['fprefdate']).date()
except KeyError:
fprefdate = timezone.now().date()
if fprefdate < startdate:
fprefdate = startdate
if fprefdate > enddate:
fprefdate = enddate
forminitial = {
'startdate':fstartdate,
'enddate':fenddate,
'preferreddate':fprefdate
}
else:
forminitial = {}
preferreddate = startdate
if preferreddate < timezone.now().date():
preferreddate = timezone.now().date()
if preferreddate > enddate:
preferreddate = enddate
forminitial = {
'startdate':startdate,
'enddate':enddate,
'preferreddate':preferreddate,
}
sessioncreateform = PlannedSessionForm(initial=forminitial)
startdate,enddate = get_dates_timeperiod(timeperiod)
sps = get_sessions(r,startdate=startdate,enddate=enddate)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
return render(request,'plannedsessioncreate.html',
{
'teams':get_my_teams(request.user),
'plan':trainingplan,
'form':sessioncreateform,
'plannedsessions':sps,
'rower':r,
@@ -12568,6 +12620,14 @@ def plannedsession_multicreate_view(request,timeperiod='thisweek',
r = getrequestrower(request,rowerid=rowerid)
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
sps = get_sessions(r,startdate=startdate,enddate=enddate)
m = Rower.objects.get(user=request.user)
@@ -12642,6 +12702,7 @@ def plannedsession_multicreate_view(request,timeperiod='thisweek',
context = {
'ps_formset':ps_formset,
'rower':r,
'plan':trainingplan,
'timeperiod':timeperiod,
'teams':get_my_teams(request.user),
'extrasessions': extrasessions+1
@@ -12667,6 +12728,14 @@ def plannedsession_teamcreate_view(request,timeperiod='thisweek',
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
sps = []
for team in teams:
res = get_sessions_manager(request.user,startdate=startdate,enddate=enddate)
@@ -12739,6 +12808,7 @@ def plannedsession_teamcreate_view(request,timeperiod='thisweek',
return render(request,'plannedsessionteamcreate.html',
{
'teams':get_my_teams(request.user),
'plan':trainingplan,
'form':sessioncreateform,
'teamform':sessionteamselectform,
'timeperiod':timeperiod,
@@ -12766,6 +12836,14 @@ def plannedsession_teamedit_view(request,timeperiod='thisweek',
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
sps = []
rowers = []
for team in teams:
@@ -12852,6 +12930,7 @@ def plannedsession_teamedit_view(request,timeperiod='thisweek',
return render(request,'plannedsessionteamedit.html',
{
'plannedsession':ps,
'plan':trainingplan,
'teams':get_my_teams(request.user),
'form':sessioncreateform,
'teamform':sessionteamselectform,
@@ -12867,6 +12946,8 @@ def plannedsessions_coach_view(request,timeperiod='thisweek',
startdate,enddate = get_dates_timeperiod(timeperiod)
trainingplan = None
if teamid != 0:
try:
theteam = Team.objects.get(id=teamid)
@@ -12916,6 +12997,7 @@ def plannedsessions_coach_view(request,timeperiod='thisweek',
{
'myteams':myteams,
'plannedsessions':sps,
'plan':trainingplan,
'statusdict':statusdict,
'timeperiod':timeperiod,
'rowers':rowers,
@@ -12931,7 +13013,16 @@ def plannedsessions_view(request,timeperiod='thisweek',rowerid=0):
r = getrequestrower(request,rowerid=rowerid)
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
sps = get_sessions(r,startdate=startdate,enddate=enddate)
completeness = {}
@@ -12954,6 +13045,7 @@ def plannedsessions_view(request,timeperiod='thisweek',rowerid=0):
{
'teams':get_my_teams(request.user),
'plannedsessions':sps,
'plan':trainingplan,
'rower':r,
'timeperiod':timeperiod,
'completeness':completeness,
@@ -12969,6 +13061,14 @@ def plannedsessions_print_view(request,timeperiod='thisweek',rowerid=0):
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
sps = get_sessions(r,startdate=startdate,enddate=enddate)
completeness = {}
@@ -12978,6 +13078,7 @@ def plannedsessions_print_view(request,timeperiod='thisweek',rowerid=0):
return render(request,'plannedsessions_print.html',
{
'teams':get_my_teams(request.user),
'plan':trainingplan,
'plannedsessions':sps,
'rower':r,
'startdate':startdate,
@@ -12998,6 +13099,14 @@ def plannedsessions_manage_view(request,timeperiod='thisweek',rowerid=0,
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
sps = get_sessions(r,startdate=startdate,enddate=enddate)
if initialsession==0:
try:
@@ -13098,6 +13207,7 @@ def plannedsessions_manage_view(request,timeperiod='thisweek',rowerid=0,
return render(request,'plannedsessionsmanage.html',
{
'teams':get_my_teams(request.user),
'plan':trainingplan,
'plannedsessions':sps,
'workouts':ws,
'timeperiod':timeperiod,
@@ -13108,6 +13218,7 @@ def plannedsessions_manage_view(request,timeperiod='thisweek',rowerid=0,
# Clone an existing planned session
# need clarity on cloning behavior time shift
@user_passes_test(hasplannedsessions,login_url="/rowers/planmembership/",
redirect_field_name=None)
def plannedsession_clone_view(request,id=0,rowerid=0,
@@ -13117,6 +13228,14 @@ def plannedsession_clone_view(request,id=0,rowerid=0,
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
try:
ps = PlannedSession.objects.get(id=id)
except PlannedSession.DoesNotExist:
@@ -13134,8 +13253,9 @@ def plannedsession_clone_view(request,id=0,rowerid=0,
ps.startdate = timezone.now().date()
ps.enddate = (timezone.now()+deltadays).date()
ps.preferreddate = ps.preferreddate+deltadays
ps.name += ' (copy)'
ps.save()
for rower in rowers:
@@ -13164,6 +13284,14 @@ def plannedsession_edit_view(request,id=0,timeperiod='thisweek',rowerid=0):
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
try:
ps = PlannedSession.objects.get(id=id)
except PlannedSession.DoesNotExist:
@@ -13213,6 +13341,7 @@ def plannedsession_edit_view(request,id=0,timeperiod='thisweek',rowerid=0):
return render(request,'plannedsessionedit.html',
{
'teams':get_my_teams(request.user),
'plan':trainingplan,
'form':sessioncreateform,
'plannedsessions':sps,
'thesession':ps,
@@ -13289,9 +13418,12 @@ def plannedsession_view(request,id=0,rowerid=0,
'distance': w.distance,
'time': dddelta,
'type': w.workouttype,
'coursecompleted':True,
}
if ps.sessiontype == 'coursetest':
vs = CourseTestResult.objects.filter(plannedsession=ps)
vs = CourseTestResult.objects.filter(plannedsession=ps,
workoutid=w.id)
if vs:
for record in vs:
if record.workoutid == w.id:
@@ -13305,20 +13437,27 @@ def plannedsession_view(request,id=0,rowerid=0,
microseconds=t.microsecond
)
wdict['distance'] = int(round(coursemeters))
wdict['coursecompleted'] = coursecompleted
else:
(
coursetimeseconds,
coursemeters,
coursecompleted
) = courses.get_time_course([w],ps.course)
intsecs = int(coursetimeseconds)
microsecs = int(1.e6*(coursetimeseconds-intsecs))
record = CourseTestResult(
userid=w.user.id,
workoutid=w.id,
plannedsession=ps,
duration=w.duration,
coursecompleted=False,
)
record.save()
job = myqueue(queue,handle_check_race_course,
w.csvfilename,w.id,ps.course.id,
record.id,mode='coursetest')
intsecs = 0
microsecs = 0
wdict['time'] = datetime.timedelta(
seconds=intsecs,
microseconds=microsecs
)
wdict['distance'] = int(round(coursemeters))
# taking workout duration plus 1 minute penalty
wdict['time'] = w.duration
wdict['distance'] = ps.course.distance
wdict['coursecompleted'] = False
ranking.append(wdict)
@@ -13327,6 +13466,14 @@ def plannedsession_view(request,id=0,rowerid=0,
# if coursetest, need to reorder the ranking
startdate,enddate = get_dates_timeperiod(timeperiod)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte = startdate,
rower = r,
enddate__gte = enddate)[0]
except IndexError:
trainingplan = None
return render(request,'plannedsessionview.html',
{
@@ -13341,6 +13488,7 @@ def plannedsession_view(request,id=0,rowerid=0,
'manager':m,
'rower':r,
'ratio':ratio,
'plan':trainingplan,
'status':status,
'results':resultsdict,
'plannedsession':ps,
@@ -14171,12 +14319,11 @@ def virtualevent_submit_result_view(request,id=0):
})
@user_passes_test(hasplannedsessions,login_url="/", redirect_field_name=None)
def rower_create_trainingplan(request,id=0):
def rower_create_trainingplan(request,userid=0):
therower = getrequestrower(request,userid=id)
therower = getrequestrower(request,userid=userid)
theuser = therower.user
if request.method == 'POST' and 'date' in request.POST:
targetform = TrainingTargetForm(request.POST)
if targetform.is_valid():
@@ -14221,10 +14368,376 @@ def rower_create_trainingplan(request,id=0):
return render(request,'trainingplan_create.html',
{
'form':form,
'rower':therower,
'plans':plans,
'targets':targets,
'targetform':targetform,
})
@user_passes_test(hasplannedsessions,login_url="/", redirect_field_name=None)
def rower_delete_trainingtarget(request,id=0):
try:
target = TrainingTarget.objects.get(id=id)
except TrainingPlan.DoesNotExist:
raise Http404("Training Plan Does Not Exist")
if checkaccessuser(request.user,target.rower):
target.delete()
messages.info(request,"We have deleted the training plan")
else:
raise PermissionDenied("Access denied")
url = reverse(rower_create_trainingplan)
return HttpResponseRedirect(url)
@user_passes_test(hasplannedsessions,login_url="/", redirect_field_name=None)
def rower_delete_trainingplan(request,id=0):
try:
plan = TrainingPlan.objects.get(id=id)
except TrainingPlan.DoesNotExist:
raise Http404("Training Plan Does Not Exist")
if checkaccessuser(request.user,plan.rower):
plan.delete()
messages.info(request,"We have deleted the training plan")
else:
raise PermissionDenied("Access denied")
url = reverse(rower_create_trainingplan)
return HttpResponseRedirect(url)
class TrainingPlanDelete(DeleteView):
model = TrainingPlan
template_name = 'trainingplan_delete.html'
success_url = reverse_lazy(rower_create_trainingplan)
def get_object(self, *args, **kwargs):
obj = super(TrainingPlanDelete, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.plan.rower):
raise Http404
return obj
class MicroCycleDelete(DeleteView):
model = TrainingMicroCycle
template_name = 'trainingplan_delete.html'
def get_success_url(self):
plan = self.object.plan.plan.plan
createmacrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs = {
'id':plan.id
})
def get_object(self, *args, **kwargs):
obj = super(MicroCycleDelete, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.plan.plan.plan.rower):
raise Http404
return obj
class MesoCycleDelete(DeleteView):
model = TrainingMesoCycle
template_name = 'trainingplan_delete.html'
def get_success_url(self):
plan = self.object.plan.plan
createmacrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs = {
'id':plan.id
})
def get_object(self, *args, **kwargs):
obj = super(MesoCycleDelete, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.plan.plan.rower):
raise Http404
return obj
class MacroCycleDelete(DeleteView):
model = TrainingMacroCycle
template_name = 'trainingplan_delete.html'
def get_success_url(self):
plan = self.object.plan
createmacrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs = {
'id':plan.id
})
def get_object(self, *args, **kwargs):
obj = super(MacroCycleDelete, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.plan.rower):
raise Http404
return obj
@user_passes_test(hasplannedsessions,login_url="/", redirect_field_name=None)
def rower_trainingplan_view(request,id=0):
try:
plan = TrainingPlan.objects.get(id=id)
except TrainingPlan.DoesNotExist:
raise Http404("Training Plan Does Not Exist")
if not checkaccessuser(request.user,plan.rower):
raise PermissionDenied("Access denied")
createmacrofillers(plan)
macrocycles = TrainingMacroCycle.objects.filter(plan=plan).order_by("startdate")
count = 0
cycles = {}
r = plan.rower
for m in macrocycles:
createmesofillers(m)
m.plantime = 0
m.actualtime = 0
m.plandistance = 0
m.actualdistance = 0
m.planrscore = 0
m.actualrscore = 0
m.plantrimp = 0
m.actualtrimp = 0
mesocycles = TrainingMesoCycle.objects.filter(plan=m).order_by("startdate")
mesos = {}
count2 = 0
for me in mesocycles:
createmicrofillers(me)
me.plantime = 0
me.actualtime = 0
me.plandistance = 0
me.actualdistance = 0
me.planrscore = 0
me.actualrscore = 0
me.plantrimp = 0
me.actualtrimp = 0
microcycles = TrainingMicroCycle.objects.filter(plan=me).order_by("startdate")
for mm in microcycles:
sps = PlannedSession.objects.filter(
rower = plan.rower,
startdate__lte=mm.enddate,
enddate__gte=mm.startdate)
mm.plantime = 0
mm.actualtime = 0
mm.plandistance = 0
mm.actualdistance = 0
mm.planrscore = 0
mm.actualrscore = 0
mm.plantrimp = 0
mm.actualtrimp = 0
if mm.type == 'userdefined':
for ps in sps:
ratio, status, cdate = is_session_complete(r,ps)
if ps.sessionmode == 'time':
mm.plantime += ps.sessionvalue
mm.actualtime += int(ps.sessionvalue*ratio)
elif ps.sessionmode == 'distance':
mm.plandistance += ps.sessionvalue
mm.actualdistance += int(ps.sessionvalue*ratio)
elif ps.sessionmode == 'rScore':
mm.planrscore += ps.sessionvalue
mm.actualrscore += int(ps.sessionvalue*ratio)
elif ps.sessionmode == 'TRIMP':
mm.plantrimp += ps.sessionvalue
mm.actualtrimp += int(ps.sessionvalue*ratio)
mm.save()
me.plantime += mm.plantime
me.actualtime += mm.actualtime
me.plandistance += mm.plandistance
me.actualdistance += mm.actualdistance
me.planrscore += mm.planrscore
me.actualrscore += mm.actualrscore
me.plantrimp += mm.plantrimp
me.actualtrimp += mm.actualtrimp
if me.type == 'userdefined':
me.save()
m.plantime += me.plantime
m.actualtime += me.actualtime
m.plandistance += me.plandistance
m.actualdistance += me.actualdistance
m.planrscore += me.planrscore
m.actualrscore += me.actualrscore
m.plantrimp += me.plantrimp
m.actualtrimp += me.actualtrimp
mesos[count2] = (me, microcycles)
count2 += 1
if m.type == 'userdefined':
m.save()
cycles[count] = (m,mesos)
count += 1
return render(request,'trainingplan.html',
{
'plan':plan,
'cycles':cycles,
}
)
class TrainingMacroCycleUpdate(UpdateView):
model = TrainingMacroCycle
template_name = 'trainingplan_edit.html'
form_class = TrainingMacroCycleForm
def get_success_url(self):
plan = self.object.plan
createmacrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs = {
'id':plan.id
}
)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
macrocycle = form.save()
mesocyclecheckdates(macrocycle)
return super(TrainingMacroCycleUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingMacroCycleUpdate, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.plan.rower):
raise Http404
else:
obj.type = 'userdefined'
obj.save()
return obj
class TrainingMesoCycleUpdate(UpdateView):
model = TrainingMesoCycle
template_name = 'trainingplan_edit.html'
form_class = TrainingMesoCycleForm
def get_success_url(self):
plan = self.object.plan
createmesofillers(plan)
return reverse(rower_trainingplan_view,
kwargs = {
'id':plan.plan.id
}
)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
mesocycle = form.save()
microcyclecheckdates(mesocycle)
return super(TrainingMesoCycleUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingMesoCycleUpdate, self).get_object(*args, **kwargs)
r = obj.plan.plan.rower
if not checkaccessuser(self.request.user,r):
raise Http404
else:
obj.type = 'userdefined'
obj.save()
obj.plan.type = 'userdefined'
obj.plan.save()
return obj
class TrainingMicroCycleUpdate(UpdateView):
model = TrainingMicroCycle
template_name = 'trainingplan_edit.html'
form_class = TrainingMicroCycleForm
def get_success_url(self):
plan = self.object.plan
createmicrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs = {
'id':plan.plan.plan.id
}
)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
microcycle = form.save()
return super(TrainingMicroCycleUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingMicroCycleUpdate, self).get_object(*args, **kwargs)
r = obj.plan.plan.plan.rower
if not checkaccessuser(self.request.user,r):
raise Http404
else:
obj.type = 'userdefined'
obj.save()
obj.plan.type = 'userdefined'
obj.plan.save()
return obj
class TrainingPlanUpdate(UpdateView):
model = TrainingPlan
template_name = 'trainingplan_edit.html'
form_class = TrainingPlanForm
def get_success_url(self):
return reverse(rower_create_trainingplan)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
plan = form.save()
macrocyclecheckdates(plan)
return super(TrainingPlanUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingPlanUpdate, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.rower):
raise Http404
return obj
class TrainingTargetUpdate(UpdateView):
model = TrainingTarget
template_name = 'trainingplan_edit.html'
form_class = TrainingTargetForm
def get_success_url(self):
return reverse(rower_create_trainingplan)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
plan = form.save()
return super(TrainingTargetUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingTargetUpdate, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.rower):
raise Http404
return obj

View File

@@ -490,6 +490,44 @@ a.button {
color: #a9c08c;
}
/* palegreen */
.palegreen {
background: palegreen;
box-shadow:inset 0px 0px 0px 6px #fff;
-moz-box-shadow:inset 0px 0px 0px 6px #fff;
box-shadow:inset 0px 0px 0px 6px #fff;
}
/* paleblue */
.paleblue {
# padding: 8px;
background: aliceblue;
box-shadow:inset 0px 0px 0px 6px #fff;
-moz-box-shadow:inset 0px 0px 0px 6px #fff;
box-shadow:inset 0px 0px 0px 6px #fff;
}
/* lightsalmon */
.lightsalmon {
# padding: 4px;
background: lightsalmon;
box-shadow:inset 0px 0px 0px 6px #fff;
-moz-box-shadow:inset 0px 0px 0px 6px #fff;
box-shadow:inset 0px 0px 0px 6px #fff;
}
/* filler */
.filler {
background: darkgray;
box-shadow:inset 0px 0px 0px 6px #fff;
-moz-box-shadow:inset 0px 0px 0px 6px #fff;
box-shadow:inset 0px 0px 0px 6px #fff;
}
.padded {
padding: 10px;
}
/* pink */
.pink {
color: #feeef5;