diff --git a/rowers/models.py b/rowers/models.py index 1d74caf9..c33b46d8 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -1073,6 +1073,7 @@ def createmacrofillers(plan): if not cycles: macr = TrainingMacroCycle( + plan=plan, startdate = plan.startdate, enddate = plan.enddate, type='filler', @@ -1095,6 +1096,131 @@ def createmacrofillers(plan): cycles = cycles[1:] +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:] + + +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:] + +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:] + +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:] + +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:] + + class TrainingMacroCycle(models.Model): plan = models.ForeignKey(TrainingPlan) name = models.CharField(max_length=150,blank=True) @@ -1127,6 +1253,12 @@ class TrainingMacroCycle(models.Model): 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") @@ -1151,11 +1283,13 @@ class TrainingMacroCycle(models.Model): ) meso.save() + else: + createmesofillers(self) class TrainingMacroCycleForm(ModelForm): class Meta: model = TrainingMacroCycle - fields = ['name','startdate','enddate'] + fields = ['name','startdate','enddate','notes'] widgets = { 'startdate': AdminDateWidget(), @@ -1181,6 +1315,49 @@ class TrainingMesoCycle(models.Model): 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) @@ -1201,15 +1378,57 @@ class TrainingMicroCycle(models.Model): return stri + def save(self, *args, **kwargs): + if self.enddate < self.startdate: + startdate = self.startdate + enddate = self.enddate + self.startdate = enddate + self.enddate = startdate -# 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 + 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/templates/trainingplan.html b/rowers/templates/trainingplan.html index 8c726804..4477b255 100644 --- a/rowers/templates/trainingplan.html +++ b/rowers/templates/trainingplan.html @@ -18,43 +18,48 @@

Training Plan - {{ plan.name }}

+

Edit

Macro Cycles

-
+

Meso Cycles

-
+

Micro Cycles

-
+
{% for key,macrocycle in cycles.items %}
-
-

{{ macrocycle.0.name }}

-

{{ macrocycle.0.startdate }}

-

{{ macrocycle.0.enddate }}

-

edit

+
+
+

{{ macrocycle.0.name }} ({{ macrocycle.0.startdate }} - {{ macrocycle.0.enddate }})

+

edit

+
-
+
{% for key, mesocycle in macrocycle.1.items %} -
- {{ mesocycle.0 }} +
+
+

{{ mesocycle.0.name }} ({{ mesocycle.0.startdate }} - {{ mesocycle.0.enddate }})

+

edit

+
- {% for key, microcycle in mesocycle.1.items %} -
- {{ microcycle }} + {% for microcycle in mesocycle.1 %} +
+
+

{{ microcycle.name }} ({{ microcycle.startdate }} - {{ microcycle.enddate }})

+

edit

+
+ {% endfor %}
{% endfor %}
- {% endfor %}
{% endfor %} -
- {% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index 2df4078f..7210e921 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -424,6 +424,8 @@ urlpatterns = [ 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()), diff --git a/rowers/views.py b/rowers/views.py index 1b0bf330..63d16ae5 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -71,7 +71,10 @@ from rowers.models import ( TrainingPlan,TrainingPlanForm,TrainingTarget,TrainingTargetForm, TrainingMacroCycle,TrainingMesoCycle,TrainingMicroCycle, TrainingTarget,TrainingTargetForm, - TrainingMacroCycleForm,createmacrofillers + TrainingMacroCycleForm,createmacrofillers, + createmicrofillers, createmesofillers, + microcyclecheckdates,mesocyclecheckdates,macrocyclecheckdates, + TrainingMesoCycleForm, TrainingMicroCycleForm, ) from rowers.models import ( RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm, @@ -14279,6 +14282,7 @@ def rower_trainingplan_view(request,id=0): if not checkaccessuser(request.user,plan.rower): raise PermissionDenied("Access denied") + createmacrofillers(plan) macrocycles = TrainingMacroCycle.objects.filter(plan=plan).order_by("startdate") count = 0 @@ -14286,10 +14290,12 @@ def rower_trainingplan_view(request,id=0): for m in macrocycles: + createmesofillers(m) mesocycles = TrainingMesoCycle.objects.filter(plan=m).order_by("startdate") mesos = {} count2 = 0 for me in mesocycles: + createmicrofillers(me) microcycles = TrainingMicroCycle.objects.filter(plan=me).order_by("startdate") mesos[count2] = (me, microcycles) count2 += 1 @@ -14318,8 +14324,12 @@ class TrainingMacroCycleUpdate(UpdateView): '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): @@ -14331,6 +14341,68 @@ class TrainingMacroCycleUpdate(UpdateView): 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() + 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() + return obj + class TrainingPlanUpdate(UpdateView): model = TrainingPlan template_name = 'trainingplan_edit.html' @@ -14343,6 +14415,7 @@ class TrainingPlanUpdate(UpdateView): 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): diff --git a/static/css/rowsandall.css b/static/css/rowsandall.css index 776bfd55..dfcc8a06 100644 --- a/static/css/rowsandall.css +++ b/static/css/rowsandall.css @@ -490,6 +490,36 @@ 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; +} + +.padded { + padding: 10px; +} + /* pink */ .pink { color: #feeef5;