Private
Public Access
1
0

Merge branch 'feature/fitnessvalues' into develop

This commit is contained in:
2025-05-29 13:42:29 +02:00
7 changed files with 122 additions and 41 deletions
+37 -11
View File
@@ -17,9 +17,9 @@ def weightfromrecord(row,metricchoice):
return 0 # pragma: no cover return 0 # pragma: no cover
def getfatigues(df, fatigues, fitnesses, dates, impulses, startdate, kfatigue, kfitness): def getfatigues(df, fatigues, fitnesses, dates, impulses, startdate, kfatigue, kfitness,actualfitness=0, actualfatigue=0):
fatigue = 0 fatigue = actualfatigue
fitness = 0 fitness = actualfitness
impulses = [] impulses = []
for f in fatigues: for f in fatigues:
@@ -57,13 +57,28 @@ def getfatigues(df, fatigues, fitnesses, dates, impulses, startdate, kfatigue, k
return fatigues, fitnesses, dates, impulses return fatigues, fitnesses, dates, impulses
def calculate_fitness(rower): def calculate_fitness(rower, reset=False):
workouts = Workout.objects.filter(user=rower, date__gte=datetime.date.today() - datetime.timedelta(days=90), try:
duplicate=False).order_by('date') w_last = Workout.objects.get(id=rower.last_workout)
datetime_last = w_last.startdatetime
except Workout.DoesNotExist:
w_last = None
datetime_last = datetime.datetime.now() - datetime.timedelta(days=90)
if reset:
rower.last_workout = 0
rower.actualfit = 0
rower.actualfatigue = 0
rower.save()
datetime_last = datetime.datetime.now() - datetime.timedelta(days=90)
workouts = Workout.objects.filter(user=rower, startdatetime__gt=datetime_last,
duplicate=False).order_by('date').exclude(id=rower.last_workout)
kfitness = rower.kfit kfitness = rower.kfit
kfatigue = rower.kfatigue kfatigue = rower.kfatigue
actualfitness = rower.actualfit
actualfatigue = rower.actualfatigue
records = [] records = []
@@ -81,13 +96,15 @@ def calculate_fitness(rower):
df = pl.from_records(records) df = pl.from_records(records)
if df.is_empty(): if df.is_empty():
return 0, 0 return actualfitness, actualfatigue
dates = [arrow.get(w.date).datetime for w in workouts] dates = [arrow.get(w.date).datetime for w in workouts]
impulses = [np.nan for w in workouts] impulses = [np.nan for w in workouts]
fitnesses = [np.nan for w in workouts] fitnesses = [np.nan for w in workouts]
fatigues = [np.nan for w in workouts] fatigues = [np.nan for w in workouts]
fatigues, fitnesses, dates, impulses = getfatigues( fatigues, fitnesses, dates, impulses = getfatigues(
df, df,
fatigues, fatigues,
@@ -95,7 +112,9 @@ def calculate_fitness(rower):
dates, dates,
impulses, impulses,
datetime.date.today()-datetime.timedelta(days=90), datetime.date.today()-datetime.timedelta(days=90),
kfatigue, kfitness kfatigue, kfitness,
actualfitness=actualfitness,
actualfatigue=actualfatigue,
) )
df = pl.DataFrame({ df = pl.DataFrame({
@@ -105,8 +124,15 @@ def calculate_fitness(rower):
'impulse': impulses, 'impulse': impulses,
}) })
endfitness = fitnesses[-2] endfitness = fitnesses[-1]
endfatigue = fatigues[-2] endfatigue = fatigues[-1]
if workouts:
enddate = workouts.last().date
rower.last_workout = workouts.last().id
rower.actualfit = int(endfitness)
rower.actualfatigue = int(endfatigue)
rower.save()
return endfitness, endfatigue return endfitness, endfatigue
-11
View File
@@ -316,17 +316,6 @@ class MetricsForm(forms.Form):
class CNsummaryForm(forms.Form): class CNsummaryForm(forms.Form):
file = forms.FileField(required=True, validators=[must_be_csv]) file = forms.FileField(required=True, validators=[must_be_csv])
class CurrentWeekJsonForm(forms.Form):
plan = forms.CharField(required=True, label="Plan Code", initial="zwolsche")
secret = forms.CharField(required=True, label="Plan Secret", initial="noot")
delete_existing = forms.BooleanField(required=False, initial=False, label="Remove any existing sessions")
class NextWeekJsonForm(forms.Form):
plan = forms.CharField(required=True, label="Plan Code", initial="zwolsche")
secret = forms.CharField(required=True, label="Plan Secret", initial="noot")
fitness = forms.IntegerField(required=False, label='Fitness', initial=0)
fatigue = forms.IntegerField(required=False, label='Fatigue', initial=0)
delete_existing = forms.BooleanField(required=False, initial=False, label="Remove any existing sessions")
# The little window to type '4x2000m/500m' to update the workout summary # The little window to type '4x2000m/500m' to update the workout summary
+47
View File
@@ -1129,6 +1129,10 @@ class Rower(models.Model):
showfit = models.BooleanField(default=False) showfit = models.BooleanField(default=False)
showfresh = models.BooleanField(default=False) showfresh = models.BooleanField(default=False)
actualfit = models.IntegerField(default=0, verbose_name='Actual Fitness')
actualfatigue = models.IntegerField(default=0, verbose_name='Actual Fatigue')
last_workout = models.BigIntegerField(default=0, verbose_name='Last Workout ID')
pw_ut2 = models.IntegerField(default=124, verbose_name="UT2 Power") pw_ut2 = models.IntegerField(default=124, verbose_name="UT2 Power")
pw_ut1 = models.IntegerField(default=171, verbose_name="UT1 Power") pw_ut1 = models.IntegerField(default=171, verbose_name="UT1 Power")
pw_at = models.IntegerField(default=203, verbose_name="AT Power") pw_at = models.IntegerField(default=203, verbose_name="AT Power")
@@ -1175,6 +1179,8 @@ class Rower(models.Model):
workoutnametemplate = WorkoutNameTemplateField(default=['date','name','distance','ownerfirst','ownerlast','duration','boattype','workouttype']) workoutnametemplate = WorkoutNameTemplateField(default=['date','name','distance','ownerfirst','ownerlast','duration','boattype','workouttype'])
# Access tokens # Access tokens
training_plan_code = models.CharField(default='', max_length=200, blank=True, null=True)
training_plan_secret = models.CharField(default='', max_length=200, blank=True, null=True)
c2token = models.CharField( c2token = models.CharField(
default='', max_length=200, blank=True, null=True) default='', max_length=200, blank=True, null=True)
tokenexpirydate = models.DateTimeField(blank=True, null=True) tokenexpirydate = models.DateTimeField(blank=True, null=True)
@@ -5205,6 +5211,47 @@ class RowerBillingAddressForm(ModelForm):
super(RowerBillingAddressForm, self).__init__(*args, **kwargs) super(RowerBillingAddressForm, self).__init__(*args, **kwargs)
self.fields['country'].required = True self.fields['country'].required = True
class NextWeekPlanForm(ModelForm):
# add some extra fields save_credentials and delete_existing to the form
delete_existing = forms.BooleanField(required=False, initial=False, label="Remove any existing sessions")
save_credentials = forms.BooleanField(required=False, initial=False, label="Save credentials for next time")
class Meta:
model = Rower
fields = ['training_plan_code',
'training_plan_secret',
'actualfit',
'actualfatigue']
def __init__(self, *args, **kwargs):
super(NextWeekPlanForm, self).__init__(*args, **kwargs)
def clean(self):
cleaned_data = super(NextWeekPlanForm, self).clean()
plan = cleaned_data.get('training_plan_code')
secret = cleaned_data.get('training_plan_secret')
save_credentials = cleaned_data.get('save_credentials')
fitness = cleaned_data.get('actualfit')
fatigue = cleaned_data.get('actualfatigue')
if not fitness or not fatigue:
raise forms.ValidationError("You need to fill in fitness and fatigue")
r = self.instance
r.actualfit = fitness
r.actualfatigue = fatigue
w = Workout.objects.filter(user=r).order_by('-date').exclude(duplicate=True)
r.last_workout = w.last().id
r.save()
if not plan or not secret:
raise forms.ValidationError("Plan Code and Secret are required")
if save_credentials:
r.training_plan_code = plan
r.training_plan_secret = secret
r.save()
return cleaned_data
# Form to set rower's Email and Weight category # Form to set rower's Email and Weight category
class AccountRowerForm(ModelForm): class AccountRowerForm(ModelForm):
+24
View File
@@ -0,0 +1,24 @@
{% extends "newbase.html" %}
{% load static %}
{% load rowerfilters %}
{% block title %}Planned Sessions{% endblock %}
{% block main %}
<h1>Load current week</h1>
<form enctype="multipart/form-data" method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Submit">
</form>
{% endblock %}
{% block sidebar %}
{% include 'menu_plan.html' %}
{% endblock %}
Binary file not shown.
+12 -18
View File
@@ -4217,13 +4217,13 @@ def planmacrocyclebymonth(request, id=0, userid=0): # pragma: no cover
def currentweekplan_view(request): def currentweekplan_view(request):
r = getrower(request.user) r = getrower(request.user)
form = CurrentWeekJsonForm() form = NextWeekPlanForm(instance=r)
if request.method == "POST": if request.method == "POST":
form = CurrentWeekJsonForm(request.POST) form = NextWeekPlanForm(request.POST, instance=r)
if form.is_valid(): if form.is_valid():
secret = form.cleaned_data['secret'] secret = form.cleaned_data['training_plan_secret']
plan = form.cleaned_data['plan'] plan = form.cleaned_data['training_plan_code']
delete_existing = form.cleaned_data['delete_existing'] delete_existing = form.cleaned_data['delete_existing']
post_data = { post_data = {
@@ -4257,12 +4257,12 @@ def currentweekplan_view(request):
}, },
{ {
'url': reverse('currentweekplan_view'), 'url': reverse('currentweekplan_view'),
'name': "Next week" 'name': "Current week"
}, },
] ]
return render(request, return render(request,
'loadnextweek.html', 'loadcurrentweek.html',
{'rower': r, {'rower': r,
'form': form, 'form': form,
'active': active, 'active': active,
@@ -4277,21 +4277,15 @@ def nextweekplan_view(request):
fitness, fatigue = calculate_fitness(r) fitness, fatigue = calculate_fitness(r)
form = NextWeekPlanForm(instance=r)
form = NextWeekJsonForm(
initial={
'fitness': round(fitness),
'fatigue': round(fatigue),
}
)
if request.method == "POST": if request.method == "POST":
form = NextWeekJsonForm(request.POST) form = NextWeekPlanForm(request.POST, instance=r)
if form.is_valid(): if form.is_valid():
fitness = form.cleaned_data['fitness'] fitness = form.cleaned_data['actualfit']
fatigue = form.cleaned_data['fatigue'] fatigue = form.cleaned_data['actualfatigue']
secret = form.cleaned_data['secret'] secret = form.cleaned_data['training_plan_secret']
plan = form.cleaned_data['plan'] plan = form.cleaned_data['training_plan_code']
delete_existing = form.cleaned_data['delete_existing'] delete_existing = form.cleaned_data['delete_existing']
post_data = { post_data = {
+2 -1
View File
@@ -121,7 +121,7 @@ from rowers.forms import (
TrainingPlanBillingForm, InstantPlanSelectForm, TrainingPlanBillingForm, InstantPlanSelectForm,
TrainingZonesForm, InstrokeForm, InStrokeMultipleCompareForm, TrainingZonesForm, InstrokeForm, InStrokeMultipleCompareForm,
ForceCurveMultipleCompareForm, PlanByRscoreForm, ForceCurveMultipleCompareForm, PlanByRscoreForm,
AssignChoices, NextWeekJsonForm, CurrentWeekJsonForm, AssignChoices,
) )
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
@@ -188,6 +188,7 @@ from rowers.models import ( RowerPowerForm, RowerHRZonesForm, SimpleRowerPowerFo
RowerExportFormConcept2, RowerExportFormGarmin, RowerExportFormConcept2, RowerExportFormGarmin,
RowerExportFormIntervals, RowerExportFormRP3, RowerExportFormIntervals, RowerExportFormRP3,
RowerExportFormNK, RowerPrivateImportForm, RowerExportFormNK, RowerPrivateImportForm,
NextWeekPlanForm,
) )
from rowers.models import ( from rowers.models import (
FavoriteForm, BaseFavoriteFormSet, SiteAnnouncement, BasePlannedSessionFormSet, FavoriteForm, BaseFavoriteFormSet, SiteAnnouncement, BasePlannedSessionFormSet,