diff --git a/rowers/courseutils.py b/rowers/courseutils.py index 75130af5..2ce31fb3 100644 --- a/rowers/courseutils.py +++ b/rowers/courseutils.py @@ -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 diff --git a/rowers/models.py b/rowers/models.py index 38151ee3..cbc298ef 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -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): diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 4134ed87..46b7f326 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -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= 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 enddate: + startdate2 = enddate + enddate = startdate + startdate = startdate2 + except ValueError: + startdate = date.today() + enddate = date.today() else: startdate = date.today() enddate = date.today() diff --git a/rowers/tasks.py b/rowers/tasks.py index 1581d28c..72f278e8 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -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() diff --git a/rowers/templates/analysis.html b/rowers/templates/analysis.html index e18454fc..56eb39e2 100644 --- a/rowers/templates/analysis.html +++ b/rowers/templates/analysis.html @@ -138,7 +138,19 @@ Analyse power vs piece duration to make predictions, for erg pieces.

-
+
+

+ {% if user|is_planmember %} + Power Progress + {% else %} + Power Progress + {% endif %} +

+

+ Monitoring power duration evidence from all your workouts. Feel free to explore. +

+
+

{% if user|is_planmember %} The Labs diff --git a/rowers/templates/laboratory.html b/rowers/templates/laboratory.html index 9b5b2964..1485f78a 100644 --- a/rowers/templates/laboratory.html +++ b/rowers/templates/laboratory.html @@ -24,13 +24,13 @@

{% if user|is_planmember %} - Power Progress + Training Target {% else %} - Power Progress + Training Target {% endif %}

- Monitoring power duration evidence from all your workouts. Feel free to explore. + Experiments with a training target and plan builder

diff --git a/rowers/templates/plannedsessionview.html b/rowers/templates/plannedsessionview.html index 8ace4c3a..34df6972 100644 --- a/rowers/templates/plannedsessionview.html +++ b/rowers/templates/plannedsessionview.html @@ -65,6 +65,7 @@ {% for result in ranking %} + {% if result|lookup:'coursecompleted' %} {{ forloop.counter }} {{ result|lookup:'name' }} @@ -73,6 +74,7 @@ {{ result|lookup:'date'|date:"Y-m-d" }} {{ result|lookup:'type' }} + {% endif %} {% endfor %} diff --git a/rowers/templates/planningbuttons.html b/rowers/templates/planningbuttons.html index 1e9c944a..57113b33 100644 --- a/rowers/templates/planningbuttons.html +++ b/rowers/templates/planningbuttons.html @@ -1,14 +1,20 @@ {% load rowerfilters %}
-

- {% if timeperiod and rower %} - Plan Overview - {% elif timeperiod %} - Plan Overview - {% else %} - Plan Overview - {% endif %} -

+

diff --git a/rowers/templates/trainingplan.html b/rowers/templates/trainingplan.html new file mode 100644 index 00000000..e3d67466 --- /dev/null +++ b/rowers/templates/trainingplan.html @@ -0,0 +1,221 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Rowsandall Training Plans{% endblock %} + +{% block scripts %} + +{% endblock %} + +{% block content %} + + +

+
+

Training Plan - {{ plan.name }}

+

This plan starts on {{ plan.startdate }} and ends on {{ plan.enddate }}. The training plan target is: {{ plan.target.name }} on {{ plan.target.date }}.

+

Edit the plan

+
+
+

Macro Cycles

+
+
+

Meso Cycles

+
+
+

Micro Cycles

+
+
+
+ {% now "Y-m-d" as todays_date %} + {% for key,macrocycle in cycles.items %} +
+ {% if macrocycle.0.type == 'filler' %} +
+ {% else %} +
+ {% endif %} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + {% if todays_date <= macrocycle.0.enddate|date:"Y-m-d" %} + + + + + + + {% endif %} +
+ {{ macrocycle.0.name }} ({{ macrocycle.0.startdate }} - {{ macrocycle.0.enddate }}) +
dist (m)t (min)rScoreTRIMP
plan{{ macrocycle.0.plandistance }}{{ macrocycle.0.plantime }}{{ maccrocycle.0.planrscore }}{{ macrocycle.0.plantrimp }}
actual{{ macrocycle.0.actualdistance }}{{ macrocycle.0.actualtime }}{{ macrocycle.0.actualrscore }}{{ macrocycle.0.actualtrimp }}
 
+ edit + / + delete + / + sessions +
+
+
+
+ {% for key, mesocycle in macrocycle.1.items %} + {% if mesocycle.0.type == 'filler' %} +
+ {% else %} +
+ {% endif %} +
+ + + + + {% if mesocycle.0.plan.type == 'userdefined' %} + + + + + + + + + + + + + + + + + + + + + + {% if todays_date <= mesocycle.0.enddate|date:"Y-m-d" %} + + + + + + + {% endif %} + {% endif %} +
+ {{ mesocycle.0.name }} ({{ mesocycle.0.startdate }} - {{ mesocycle.0.enddate }}) +
dist (m)t (min)rScoreTRIMP
plan{{ mesocycle.0.plandistance }}{{ mesocycle.0.plantime }}{{ mesocycle.0.planrscore }}{{ mesocycle.0.plantrimp }}
actual{{ mesocycle.0.actualdistance }}{{ mesocycle.0.actualtime }}{{ mesocycle.0.actualrscore }}{{ mesocycle.0.actualtrimp }}
 
+ edit + / + delete + / + sessions +
+
+
+
+ {% for microcycle in mesocycle.1 %} + {% if microcycle.type == 'filler' %} +
+ {% else %} +
+ {% endif %} +
+ + + + + {% if microcycle.plan.type == 'userdefined' %} + + + + + + + + + + + + + + + + + + + + + + {% if todays_date <= microcycle.enddate|date:"Y-m-d" %} + + + + + + + {% endif %} + {% endif %} +
+ {{ microcycle.name }} ({{ microcycle.startdate }} - {{ microcycle.enddate }}) +
dist (m)t (min)rScoreTRIMP
plan{{ microcycle.plandistance }}{{ microcycle.plantime }}{{ microcycle.planrscore }}{{ microcycle.plantrimp }}
actual{{ microcycle.actualdistance }}{{ microcycle.actualtime }}{{ microcycle.actualrscore }}{{ microcycle.actualtrimp }}
 
+ edit + / + delete + / + sessions +
+
+
+ {% endfor %} +
+ {% endfor %} +
+
+ {% endfor %} +
+
+

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.

+

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.

+

Click on "Sessions" in the cycle of your interest to see details + of the individual training sessions planned for this period.

+

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.

+
+ {% endblock %} diff --git a/rowers/templates/trainingplan_create.html b/rowers/templates/trainingplan_create.html index 1a4f2c29..350e2119 100644 --- a/rowers/templates/trainingplan_create.html +++ b/rowers/templates/trainingplan_create.html @@ -15,7 +15,23 @@ } -
+
+ {% if user.is_authenticated and user|is_manager %} + + {% endif %} +
+ + +

Training Targets

@@ -34,6 +50,8 @@ {{ target.date }} {{ target.name }} {{ target.notes }} + Edit + Delete {% endfor %} @@ -62,8 +80,8 @@
-
- +
+

Plans

@@ -81,7 +99,10 @@ {{ plan.startdate }} {{ plan.enddate }} - {{ plan.name }} + {{ plan.name }} + Edit + Plan + Delete {% endfor %} diff --git a/rowers/templates/trainingplan_delete.html b/rowers/templates/trainingplan_delete.html new file mode 100644 index 00000000..ffb9362c --- /dev/null +++ b/rowers/templates/trainingplan_delete.html @@ -0,0 +1,30 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Rowsandall Training Plans{% endblock %} + +{% block scripts %} + +{% endblock %} + +{% block content %} + + +
+ +
+ {% csrf_token %} +

Are you sure you want to delete {{ object }}?

+
+ +
+
+ + +
+ {% endblock %} diff --git a/rowers/templates/trainingplan_edit.html b/rowers/templates/trainingplan_edit.html new file mode 100644 index 00000000..1dc67326 --- /dev/null +++ b/rowers/templates/trainingplan_edit.html @@ -0,0 +1,32 @@ +{% extends "base.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Rowsandall Training Plans{% endblock %} + +{% block scripts %} + +{% endblock %} + +{% block content %} + + +
+ +
+ {% csrf_token %} + + {{ form.as_table }} +
+
+ +
+
+ + +
+ {% endblock %} diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 80e888a7..dede3b70 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -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 diff --git a/rowers/uploads.py b/rowers/uploads.py index 2304e37d..d871d870 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -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') diff --git a/rowers/urls.py b/rowers/urls.py index 5e0b41e0..f89c1716 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -420,7 +420,19 @@ urlpatterns = [ url(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P[\w\ ]+.*)/$',views.workout_comparison_view2), url(r'^test\_callback',views.rower_process_testcallback), url(r'^createplan$',views.rower_create_trainingplan), - url(r'^createplan/(?P\d+)$',views.rower_create_trainingplan), + url(r'^createplan/(?P\d+)$',views.rower_create_trainingplan), + url(r'^deleteplan/(?P\d+)$',views.TrainingPlanDelete.as_view()), + url(r'^deletemicrocycle/(?P\d+)$',views.MicroCycleDelete.as_view()), + url(r'^deletemesocycle/(?P\d+)$',views.MesoCycleDelete.as_view()), + url(r'^deletemacrocycle/(?P\d+)$',views.MacroCycleDelete.as_view()), +# url(r'^deleteplan/(?P\d+)$',views.rower_delete_trainingplan), + url(r'^plan/(?P\d+)$',views.rower_trainingplan_view), + url(r'^macrocycle/(?P\d+)$',views.TrainingMacroCycleUpdate.as_view()), + url(r'^mesocycle/(?P\d+)$',views.TrainingMesoCycleUpdate.as_view()), + url(r'^microcycle/(?P\d+)$',views.TrainingMicroCycleUpdate.as_view()), + url(r'^deletetarget/(?P\d+)$',views.rower_delete_trainingtarget), + url(r'^editplan/(?P\d+)$',views.TrainingPlanUpdate.as_view()), + url(r'^edittarget/(?P\d+)$',views.TrainingTargetUpdate.as_view()), url(r'^workout/(?P\d+)/test\_strokedata$',views.strokedataform), url(r'^sessions/teamcreate$',views.plannedsession_teamcreate_view), diff --git a/rowers/views.py b/rowers/views.py index 9a1bc520..7a232db9 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -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 + diff --git a/static/css/rowsandall.css b/static/css/rowsandall.css index 776bfd55..95fd1d8b 100644 --- a/static/css/rowsandall.css +++ b/static/css/rowsandall.css @@ -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;